功能模板的非依赖默认模板参数是否允许SFINAE?

时间:2013-03-06 13:42:09

标签: c++ templates language-lawyer sfinae

这里的“非依赖”是指“不依赖于该特定函数模板的任何其他模板参数”。

在回答this question时,我认为我找到了答案,但根据@Johannes(在我的回答评论中),我在这里误解了标准。采用以下简单示例:

#include <type_traits>

template<class T>
struct X{
  template<class U = typename T::type>
  static void foo(int){}
  static void foo(...){}
};

int main(){
  X<std::enable_if<false>>::foo(0);
}

Live version.

是否有保证以上编译? GCC和Clang在这里不同意,正如在实时版本中切换时所见。有趣的是,GCC接受了以下内容:

#include <type_traits>

template<class T>
struct X{
  template<bool = T::f()>
  static void foo(int){}
  static void foo(...){}
};

struct Y{
  static bool f(){ return true; }
};

int main(){
  X<Y>::foo(0);
}

Live version.

如果foo(int)包含T静态函数constexpr,则第二个代码段将仅打印f。有趣的是,如果您从f完全删除Y(或者通过,例如,int),GCC会抱怨缺少会员,表明它不允许SFINAE - 这与之前的观察相矛盾。 Clang采用所有变体并应用SFINAE,我想知道这是否是标准所保证的。

(FWIW,带有Nov CTP的MSVC通常与Clang一致,但如果该功能存在,则会在第二个代码段崩溃,可能是因为他们没有constexpr。我提交了一个错误报告{{3} }。)

1 个答案:

答案 0 :(得分:3)

我认为有问题的代码是不正确的,因为在实例化类模板时,除了成员函数和成员函数模板的定义部分和默认参数之外,所有成员声明都被实例化。标准还定义了何时精确实例化函数默认参数。

所以默认模板参数会立即被实例化。在我看来,此时默认参数可能包含默认模板参数的可能性非常小,因为没有描述何时这样的参数将是稍后实例化。

这符合要求“不应在模板参数列表中指定默认模板参数,该模板参数列表出现在成员类之外的类模板成员的定义中。” ,因为在实例化周围的类模板时,不会立即实例化这样的模板参数。