我正在尝试制作一些可以读取或写入不同类型的文件流。除了具有特定方法的阅读部分外,一切都有效。该方法在被调用时返回std::unique_ptr<T>
,并且是另一个返回T
的方法的“包装器”。由于某种原因,编译器不使用此方法,而是尝试使用其他方法(返回T
的方法)编译它。由于这个原因,编译失败了。我已经尝试在互联网上搜索,但我找不到任何准确的答案。你能帮我解决这个问题。
我定义的两种方法:
template <typename T>
T read()
{
T obj;
obj.readFromFile<T>();
return std::move(obj);
}
和
template <
typename T,
template<typename> class D,
template<typename, typename> class Container
>
typename std::enable_if_t<
std::is_same<Container<T, D<T>>, std::unique_ptr<T, D<T>>>::value,
Container<T, D<T>>
>
read()
{
return std::move(std::make_unique<T, D<T>>(readFromFile<T>()));
}
后一种方法是我试图调用的方法。
当我写这样的东西时:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>()
编译器尝试使用第一种方法(template <typename T> T read() {...}
)编译它,并且编译失败。如果我首先提出unique_ptr object
而不是将副本分配给*unique_ptr<A> object
,我可以完成这项工作但是这对我没有好处,因为我在这两个函数上使用了一些宏而我无法生成{{1}或者在调用宏之前对象自身。仅供参考,我使用的是Visual Studio 2015。
有没有办法让这项工作没有任何重大修改?我还发现了一个建议,基本上说你必须在一个函数中添加一个指针参数,然后用unique_ptr<A> object
作为参数调用它,但这在我的例子中并不重要。
感谢您的帮助。
更新 我只是想说下面的所有解决方案对我都有用,但解决问题的最简单方法是Barry提供的解决方案。 再次帮助我!
答案 0 :(得分:3)
您似乎想要部分专业化,并且由于无法对功能进行部分专业化,您可以转发到课程:
template <typename T> struct helper
{
T operator() const
{
T obj;
obj.readFromFile<T>();
return obj;
}
};
template <typename T, typename D>
struct helper<std::unique_ptr<T, D>>
{
std::unique_ptr<T, D> operator() const
{
return std::make_unique<T, D>(readFromFile<T>());
}
};
template <typename T>
T read()
{
return helper<T>{}();
}
答案 1 :(得分:1)
问题是,虽然我理解你的意图:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>();
你实际上并没有调用你认为的功能。您有两个read
重载:
template <class T> T read();
template <class T,
template<typename> class D,
template<typename, typename> class Container
> T read();
第一个有一个模板参数,第二个有3个(和一些sfinae)。但是你只用一个模板参数调用read()
,所以第二个重载 - 你想要的那个 - 甚至都不是一个选项。
对于这些情况,我喜欢简单的标记调度,以便我们可以重载而不必专门化:
template <class T> struct tag{};
template <class T> T read() { return read(tag<T>{}); }
template <class T>
T read(tag<T> ) {
T obj;
obj.readFromFile<T>();
return obj; // <== NB: no move() here! That inhibits RVO
}
template <class T, class D>
std::unique_ptr<T, D> read(tag<std::unique_ptr<T, D>> ) {
/* unique_ptr case */
}
答案 2 :(得分:1)
T
,D
和ContainerType
。我觉得你可能只希望传递一种类型,然后推断它是否是std::unique_ptr
。std::make_unique
并指定删除类型。您必须使用新创建的对象调用std::unique_ptr
构造函数。std::unique_ptr
。这是做你想做的事的一种方法。
#include <memory>
#include <type_traits>
template<typename T>
T readFromFile() { return T(); }
template<typename T, typename D>
void helper(std::unique_ptr<T, D>);
template<typename T, typename = void>
struct is_unique_ptr : std::false_type {};
template<typename T>
struct is_unique_ptr<T, decltype(helper(std::declval<T>()))> : std::true_type {};
template<typename T, typename = std::enable_if_t<!is_unique_ptr<T>::value>>
T read()
{
return readFromFile<T>();
}
template<typename P, typename = std::enable_if_t<is_unique_ptr<P>::value>, typename = void>
P read()
{
using T = typename P::element_type;
return P(new T(readFromFile<T>()));
}
int main()
{
read<std::unique_ptr<int>>();
read<int>();
}