Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;名称相同但返回类型不同的模板函数_C++_Templates - Fatal编程技术网

C++ C++;名称相同但返回类型不同的模板函数

C++ C++;名称相同但返回类型不同的模板函数,c++,templates,C++,Templates,我试图使一些文件流光,可以读取或写入不同的类型。除了有特定方法的阅读部分外,其他一切都正常。该方法在调用时返回std::unique_ptr,是另一个返回T的方法的“包装器”。出于某种原因,编译器不使用此方法,而是尝试使用另一个方法(返回T)对其进行编译。因此编译失败。我已经试着在互联网上搜索,但我找不到任何准确的答案。你能帮我做这个吗 我定义的两种方法: template <typename T> T read() { T obj; obj.readFromFi

我试图使一些文件流光,可以读取或写入不同的类型。除了有特定方法的阅读部分外,其他一切都正常。该方法在调用时返回
std::unique_ptr
,是另一个返回
T
的方法的“包装器”。出于某种原因,编译器不使用此方法,而是尝试使用另一个方法(返回
T
)对其进行编译。因此编译失败。我已经试着在互联网上搜索,但我找不到任何准确的答案。你能帮我做这个吗

我定义的两种方法:

template <typename T>
T read()
{
     T obj;
     obj.readFromFile<T>();
     return std::move(obj);
}
模板
T read()
{
T-obj;
obj.readFromFile();
返回标准::移动(obj);
}

模板<
类型名T,
模板类别D,
模板类容器
>
typename std::启用\u如果\u t<
std::值是否相同,
容器
>
读()
{
返回std::move(std::make_unique(readFromFile());
}
后一种方法就是我试图调用的方法

当我这样写的时候:

std::unique\ptr AfromFile=fileStreamer.read()

编译器尝试使用第一个方法(
template T read(){…}
)编译它,但编译失败。如果我先创建了
唯一的\u ptr对象
,然后对
*唯一的\u ptr对象
执行复制赋值,我就可以实现这一点,但这对我没有好处,因为我在这两个函数上使用了一些宏,在调用宏之前,我无法创建
唯一的\u ptr对象
或对象本身。仅供参考,我正在使用Visual Studio 2015

有没有办法不做任何重大修改就完成这项工作?我还发现了一个建议,基本上说您必须向一个函数添加一个指针参数,然后使用
static\u cast(nullptr)
作为参数调用它,但这在我的示例中不算

谢谢你的帮助

更新: 我只想说一句,下面所有的解决方案都对我有效,但是解决我的问题最简单的方法是Barry提供的解决方案。
再次感谢你帮助我

似乎您需要部分专门化,并且由于函数的部分专门化是不可能的,您可以转发到类:

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>{}();
}
模板结构帮助器
{
T运算符()常量
{
T-obj;
obj.readFromFile();
返回obj;
}
};
模板
结构辅助程序
{
std::unique_ptr运算符()常量
{
return std::make_unique(readFromFile());
}
};
模板
T read()
{
返回帮助程序{}();
}

问题在于,尽管我理解您的意图:

std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>();
第一个有一个模板参数,第二个有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 */
}
模板结构标记{};
模板T read(){返回读取(标记{});}
模板
T读取(标签){
T-obj;
obj.readFromFile();
返回obj;//
  • 一个函数不能有两个只因返回类型不同而不同的重载。必须使用SFINAE确保对任何给定模板参数只启用一个重载
  • 在第二个重载中,您试图推断模板参数的方式是错误的。目前,在调用函数时,您必须指定
    T
    D
    ContainerType
    。我感觉您可能只想传递一个类型,然后推断它是否是
    std::unique\u ptr
  • 不能调用
    std::make_unique
    并指定删除器类型。必须使用新创建的对象调用
    std::unique_ptr
    构造函数
  • 您不需要显式移动返回的
    std::unique\u 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>();
    }
    
    #包括
    #包括
    模板
    T readFromFile(){返回T();}
    模板
    void helper(std::unique_ptr);
    模板
    结构是唯一的\u ptr:std::false\u type{};
    模板
    结构是唯一的\u ptr:std::true\u类型{};
    模板>
    T read()
    {
    返回readFromFile();
    }
    模板
    P read()
    {
    使用T=typename P::element\u type;
    返回P(新的T(readFromFile());
    }
    int main()
    {
    read();
    read();
    }
    
    您必须调用
    fileStreamer.read()
    …你是对的,事实上我调用这个方法时使用了错误的参数数。在我像你建议的那样输入了正确的参数数之后,代码编译器感谢你的建议。这个解决方案是解决我问题的最简单的方法。哦,我使用std::move,因为我希望所有对象都应该有move/assign构造函数。
    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 */
    }
    
    #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>();
    }