禁止自动类型推断

时间:2012-03-30 14:52:30

标签: c++ templates overload-resolution

我有以下演示代码:

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个参数的模板)?

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_ifis_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});
}