在使用Visual C++时,使用模板特化时出现编译器错误。

6

我有以下的cpp代码:

#include <iostream>
#include <limits>

// C2589 when compiling with specialization, fine when compiling without
template<typename T>
void foo(T value = std::numeric_limits<T>::infinity() )
{
}

// this specialization causes compiler error C2589 above
template<>
void foo<float>( float value )
{
}

int main()
{
    foo<float>();
    return 0;
}

当我尝试使用Visual Studio 2013编译它时,我会收到以下错误信息:
..\check2\main.cpp(5) : error C2589: '::' : illegal token on right side of '::'
..\check2\main.cpp(5) : error C2059: syntax error : '::'

如果我不包括特化的foo<float>,程序编译正常。在gcc 4.8.4下,包括特化后的代码也可以编译成功,这表明Visual C++编译器存在一些问题。
这段代码是否正确并且应该编译?有没有Visual C++的解决方法?

我在VS2015上也遇到了同样的错误,但是它在这里编译通过了。 - Fantastic Mr Fox
@Ben:说得好。我不知道这个网站。我无法确定他们使用哪个编译器,但既然它可以成功编译,我就假设它是gcc。令我困惑的是,为什么它可以用gcc编译通过,但在VC++中却失败了。 - dkoerner
2个回答

3
当你在调用foo<float>();时省略了参数,这会让编译器感到困惑。因为你明确指定了<float>,编译器会同时认为使用特化函数和不使用特化函数都是正确的选择,但实际上没有参数无法调用通用版本,而特化版本又存在,这就让编译器很难做出选择。除非是使用gcc编译的HAL9000,否则它也无法解决这个问题。VC++不正确地处理了这种情况,这可能是一个错误,而不是“按设计要求”。

在Visual C++中的解决方法是使用重载:

template<typename T>
void foo(T value)
{
}

template<typename T>
void foo()
{
    foo(std::numeric_limits<T>::infinity());
}

像往常一样调用它:foo<float>();


OP所观察到的错误信息很奇怪。有任何想法为什么会出现那个特定的错误信息? - mindriot
1
我认为这是MSVS函数解析中的一个错误。Clang、g++和ICC都可以编译OP的问题,没有任何问题。 - NathanOliver
@mindriot 我只能猜测编译器调用了基础模板,但并没有"清晰地思考",因此无法实际使用基础模板。那个特定的消息为什么并不重要。这是一个错误。 - Dialecticus
我对这个答案并不完全信服:
  1. 禁止为模板特化指定默认参数的事实意味着函数模板中的默认参数也适用于其特化(请参见此处)。
  2. 如果存在导致问题的歧义,我希望编译器会说明。
  3. 讨论的代码应该在各种编译器上(无法)一致地编译。对我来说,这暗示了VC++存在更深层次的问题。
- dkoerner

-1

我不使用"template"关键字进行特化,而是使用重载的方式,如下:

template<typename T>
void foo(T value)
{
}

void foo(float value)
{
}

我在gcc和Visual Studio 2012中使用它们。


2
这不是专业化,而是重载。 - NathanOliver
如果编译器不能正确地执行特化,那么重载似乎是解决问题的好方法,这也是原始问题的一部分。 - Kyle A
我同意,但是“当我进行特化时,我不使用‘template’关键字,就像这样:”的意思是,当你进行特化时,你使用以下代码。我想告诉你,这根本不是特化,而是重载。你可以这样表达:“不要对模板进行特化,而是添加一个接受‘float’类型的重载函数。” - NathanOliver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接