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



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

在回答这个问题时,我以为我找到了答案,但是根据@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);
}

(活版本。)

能保证上面的编译吗? 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);
}

(活版本。)

如果T包含constexpr静态函数f,则第二个代码片段将只打印foo(int)。再一次,有趣的是,如果你完全从Y中删除f(或者通过,比如说,int), GCC会抱怨缺少一个成员,表明它不允许SFINAE——这与之前的观察结果是矛盾的。Clang接受所有的变化并应用SFINAE,我想知道这是否是标准所保证的。

(fww,带有Nov CTP的MSVC通常同意Clang,但如果函数存在,则在第二个代码片段上崩溃,可能是因为它们没有constexpr。我在这里提交了一个bug报告

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

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

这符合"默认模板实参不能在出现在成员所属类之外的类模板成员定义的模板形参列表中指定"的要求。

,因为在实例化周围的类模板时,不可能立即实例化这样的模板参数。

最新更新