Почему class :: class :: class :: staticClassMember () компилируется (в C ++)? - PullRequest
3 голосов
/ 25 марта 2019

Я, должно быть, что-то пропустил в спецификации C ++, потому что не могу объяснить, почему следующий код успешно компилируется:

class MyClass { static void fun(); };
int main() { MyClass::MyClass::MyClass::fun(); }

Может ли кто-нибудь указать мне на стандарт или просто объяснить мне семантику? Я предполагаю, что только один 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
}

Мой вопрос состоит из двух частей:

  • Какова точная семантика MyClass::MyClass::?
  • Как исправить приведенный выше пример, чтобы не компилировать callWorkout<SubClass>()? (Я пытался добавить sizeof(typename T::SubClass), но на удивление он компилируется и для T=SubClass)

1 Ответ

6 голосов
/ 25 марта 2019

Это введенное имя класса 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(); }

Если вам не нужен SFINAE (потому что вы не пытаетесь контролировать разрешение перегрузки), тогдаstatic_assert с описательным настраиваемым сообщением также может хорошо работать.

...