我有以下演示代码:
template <int i, typename T, typename U>
T func(const U &t){return i * t;}
template <int i, typename T>
T func(const T &t){return 2 * i * t;}
int main()
{
return func<1, int>(1);
}
这是我的真实代码的简化版本,所以它似乎没用,但应该足以显示问题:
In function ‘int main()’:
11:23: error: call of overloaded ‘func(int)’ is ambiguous
11:23: note: candidates are:
2:3: note: T func(const U&) [with int i = 1, T = int, U = int]
5:3: note: T func(const T&) [with int i = 1, T = int]
很明显,自动类型推断(对于模板参数U)干扰了我选择正确版本的模板函数(只有2个参数的函数)的兴趣。
我需要两个版本都有一个基本模板和一个专门的模板,它们会做一些不同的事情。
所以问题是:是否有可能告诉编译器此时不要自动推断类型(例如通过某种方式说:采用只有2个参数的模板)?
答案 0 :(得分:4)
您无法禁用类型推断,但您可以使用SFINAE来禁止其中一个重载:
template <int N, typename T, typename U>
typename std::enable_if< !std::is_same<T,U>::value, T >::type
func( const U & t ) {
return i*t;
}
这基本上创建了一个模板化函数,如果推断类型U
是类型T
,则替换将失败,此时SFINAE将从潜在候选集和其他模板中删除模板将被接走。
如果您没有启用C ++ 11的编译器,enable_if
和is_same
模板很容易编写...只需谷歌搜索或删除评论。
答案 1 :(得分:1)
你可以传递一个初始化列表,它有效地禁用了演绎(但是导致参数的列表初始化,在这种情况下int
具有相同的效果):
template <int i, typename T, typename U>
T func(const U &t){return i * t;}
template <int i, typename T>
T func(const T &t){return 2 * i * t;}
int main()
{
return func<1, int>({1});
}
但是在你的情况下,如果你打电话给func<N>(...)
,你似乎想打电话给第二个,如果你打电话给func<N, T>(...)
,你似乎总是想打电话给第二个,而且只是为了func<N, T, U>(...)
您要调用第一个,因此您可以始终通过使参数成为非限制性上下文来禁用U
的扣除
template <int i, typename T, typename U>
T func(typename std::common_type<const U &t>::type t){return i * t;}
template <int i, typename T>
T func(const T &t){return 2 * i * t;}
int main()
{
return func<1, int>({1});
}