7

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

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

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

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

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

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

4

2 回答 2

8

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

long n = static_cast<long(*)(double)>(&foo)(d);
于 2012-12-03T13:36:31.130 回答
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);
}
于 2012-12-03T13:59:31.277 回答