我注意到用于区分唯一模板函数的签名与用于区分唯一函数的签名(包括那些从模板函数实例化的签名)之间存在不对称性。
特别是,仅由返回类型不同的模板函数被认为是唯一的,而仅由返回类型不同的函数被认为是多余的。
因此,我有一个相应的问题,关于如何在实例化之间消除仅由返回类型不同的函数模板之间的歧义:
#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
的实例化是不明确的,因为我刚刚提到的不对称性。两个模板函数定义的存在是合法的,但实例化是非法的,即使返回类型在同一行代码中指定。
我纯粹是出于理论学习目的而提出这个问题。也许这种代码构造在现实生活中会成为糟糕设计的标志。也许它永远不会出现在现实生活中。此外,我可以通过更改模板定义(或进行其他更改)来设想克服此问题的不同方法。
但是,我仍然想知道,如果保持模板定义不变,可以在实例化时消除这两个模板函数之间的歧义。
答案 0 :(得分:6)
使用模板时,您实际上可以消除两种不同的重载歧义。它不漂亮但有效:
long n = static_cast<long(*)(double)>(&foo)(d);
答案 1 :(得分:1)
如果你真的需要两个具有相同名称,相同参数列表但不同返回类型的函数模板,你别无选择,只能通过使返回类型成为模板参数来区分这两个:
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);
}
在这两种情况下,你的主要看起来像这样:
int main()
{
double d = 0.0;
long n = foo<long>(d); // specify the return type only
auto c = foo<char>(n);
}