【问题标题】:How to disambiguate function templates that differ only by return type?如何消除仅因返回类型不同而不同的函数模板?
【发布时间】:2012-12-03 13:28:55
【问题描述】:

我注意到用于区分唯一模板函数的签名与用于区分唯一函数(包括从模板函数实例化的函数)的签名之间存在不对称。

特别是,仅返回类型不同的模板函数被认为是唯一的,而仅返回类型不同的函数被认为是冗余的。

因此,我有一个相应的问题,关于如何在实例化时消除仅因返回类型不同的函数模板之间的歧义:

#include <iostream>

template<typename T>
long foo(T)
{
    std::cout << "long" << std::endl;
    return 0;
}

template<typename T>
char foo(T)
{
    std::cout << "char" << std::endl;
    return '\0';
}

int main()
{
    double d = 0.0;
    long n = foo(d); // <- Ambiguous: How to specify the template function to use?
}

在上面的代码中,模板函数foo 的实例化是模棱两可的,正是因为我刚才提到的不对称性。两个模板函数定义的存在是合法的,但实例化是非法的,即使在同一行代码中指定了返回类型。

我问这个问题纯粹是为了理论学习。也许这个代码结构,在现实生活中,将是糟糕设计的标志。也许它永远不会在现实生活中出现。此外,我可以设想通过更改模板定义(或进行其他更改)来克服此问题的不同方法。

但是,我仍然想知道,在保持模板定义不变的情况下,是否可以在实例化时消除这两个模板函数之间的歧义。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    使用模板时,您实际上可以消除两种不同的重载的歧义。它不漂亮但有效:

    long n = static_cast<long(*)(double)>(&foo)(d);
    

    【讨论】:

    • +1,从来没有想过这个。丑陋但正确。顺便说一句,static_cast&lt;long(&amp;)(double)&gt;(foo)(d) 减少了 1 个字符 :)
    • 完美。现在我恢复了对函数模板的信心。我开始想知道为什么函数模板签名包含返回类型——如果它们永远无法消除歧义。但是,正如您出色的回答所揭示的那样,他们可以。
    【解决方案2】:

    如果您确实需要两个具有相同名称、相同参数列表但返回类型不同的函数模板,您别无选择,只能通过将返回类型作为模板参数来区分两者:

    template <typename R, typename T>
    R foo(T);
    

    IIRC 在 C++11 中有部分函数模板专业化,尽管我在标准中找不到任何关于它的内容。如果有,这应该有效:

    //partial function template specializations: C++11 only!
    template <typename T>
    long foo<long, T>(T)
    {
        std::cout << "long" << std::endl;
        return 0;
    }
    
    template<typename T>
    char foo<char, T>(T)
    {
        std::cout << "char" << std::endl;
        return '\0';
    }
    

    否则,在 C++03 中:

    template <typename R, typename T>
    struct FooImpl;
    
    template <typename T>
    struct FooImpl<long, T>
    {
      static long doIt(T) 
      {
        std::cout << "long" << std::endl;
        return 0;
      }
    };
    
    template <typename T>
    struct FooImpl<char, T>
    {
      static char doIt(T) 
      {
        std::cout << "char" << std::endl;
        return '\0';
      }
    };
    
    template <typename R, typename T>
    R foo(T t)
    {
      return FooImpl<R, T>::doIt(t);
    }
    

    在这两种情况下,你的 main 应该是这样的:

    int main()
    {
        double d = 0.0;
        long n = foo<long>(d); // specify the return type only
        auto c = foo<char>(n);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 2023-03-26
      • 2019-12-18
      • 2020-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多