为什么class :: class :: class :: staticClassMember()编译(在C ++中)?

Jar*_*k C 3 c++ static-methods sfinae language-lawyer name-lookup

我一定错过了C ++规范中的某些内容,因为我无法解释为什么以下代码成功编译:

class MyClass { static void fun(); };
int main() { MyClass::MyClass::MyClass::fun(); }
Run Code Online (Sandbox Code Playgroud)

有人可以指出我的标准还是要向我解释语义?我猜想只MyClass::允许一个。两个MyClass::MyClass::应该引起错误。我尝试使用MS Visual C ++ 2017和GNU C ++ 6.2.0进行了计数MyClass::

这不仅是一个理论问题。我想在存在子类的情况下使用SFINAE和条件编译。在基类的名称与子类的名称相同之前,效果良好:

template <class T> void callWorkout() { T::SubClass::workout(); }
struct X { struct SubClass { static void workout(); }; };
struct Y { /*empty*/ };
struct SubClass { static void workout(); };

int main() {
  callWorkout<X>();  // works fine - compiled
  callWorkout<Y>();  // works "fine" - not compiled, no SubClass in Y
  callWorkout<SubClass>();  // ooops? - still compiled, there is no 'SubClass' in SubClass
}
Run Code Online (Sandbox Code Playgroud)

我的问题分为两部分:

  • 的确切语义是MyClass::MyClass::什么?
  • 如何解决以上示例无法编译的问题callWorkout<SubClass>()?(我尝试添加,sizeof(typename T::SubClass)但令人惊讶的是它也为编译T=SubClass

Sto*_*ica 6

那是注入的类名MyClass。您可以T通过简单地std::is_same_v<T, typename T::SubClass>在SFINAE条件中使用来验证它不是。

template <class T>
auto callWorkout() -> std::enable_if_t<!std::is_same_v<T, typename T::SubClass>>
{ T::SubClass::workout(); }
Run Code Online (Sandbox Code Playgroud)

如果您不需要SFINAE(因为您不想控制重载分辨率),那么static_assert带有描述性自定义消息的a也可以很好地实现。