Что такое decltype с двумя аргументами?

Измените, чтобы избежать путаницы: decltype не принимает два аргумента. Посмотри ответы.

Следующие две структуры могут использоваться для проверки существования функции-члена в типе T во время компиляции:

 // Non-templated helper struct: struct _test_has_foo { template static auto test(T* p) -> decltype(p->foo(), std::true_type()); template static auto test(...) -> std::false_type; }; // Templated actual struct: template struct has_foo : decltype(_test_has_foo::test(0)) {}; 

Я думаю, идея состоит в том, чтобы использовать SFINAE при проверке существования функции-члена, поэтому в случае, если p->foo() недействителен, определяется только эллиптическая версия test , которая возвращает std::false_type . В противном случае первый метод определен для T* и вернет std::true_type . Фактический «переключатель» происходит во втором classе, который наследуется от типа, возвращаемого test . Это кажется умным и «легким» по сравнению с разными подходами с is_same и тому подобным.

decltype с двумя аргументами удивил меня, поскольку я думал, что он просто получает тип выражения. Когда я увидел код выше, я подумал, что это что-то вроде «попытайтесь скомпилировать выражения и всегда возвращать тип второго. Не удалось, если выражения не скомпилируются» (так что скройте эту специализацию, SFINAE).

Но:

Затем я подумал, что могу использовать этот метод для записи любой проверки «допустимое выражение», если это зависит от некоторого типа T Пример:

 ... template static auto test(T* p) -> decltype(bar(*p), std::true_type()); ... 

http://ideone.com/dJkLPF

Это, как я думал, вернет std::true_type тогда и только тогда, когда bar определена, принимая T в качестве первого параметра (или если T является конвертируемой и т. Д.), То есть: если bar(*p) будет компилироваться если он был написан в некотором контексте, где p задано типа T* .

Однако приведенная выше модификация всегда оценивает значение std::false_type . Почему это? Я не хочу исправлять его с помощью некоторого сложного кода. Я просто хочу знать, почему это не работает, как я ожидал. Ясно, что decltype с двумя аргументами работает иначе, чем я думал. Я не мог найти никакой документации; это объясняется только одним выражением.

Это список выражений, разделенных запятыми, тип идентичен типу последнего выражения в списке. Обычно это используется для проверки того, что первое выражение действительно (компилируемое, думаю, SFINAE), второе используется для указания того, что decltype должен возвращаться в случае, если первое выражение действительно.

decltype не принимает два аргумента. Просто он может иметь выражение как свой аргумент, а оператор запятой – один из способов создания выражений. В пункте 5.18 / 1:

[…] Пара выражений, разделенных запятой, оценивается слева направо; левое выражение является выражением отбрасываемого значения (раздел 5). Каждое вычисление значения и побочный эффект, связанные с левым выражением, секвенируются перед вычислением каждого значения и побочным эффектом, связанным с правильным выражением. Тип и значение результата – это тип и значение правильного операнда ; результат имеет такую ​​же категорию значений, что и его правый операнд, и является битовым полем, если его правый операнд – это значение glvalue и бит-поле. Если значение правого операнда является временным (12.2), результат будет временным.

Следовательно:

 static_assert(std::is_same::value, "Will not fire"); 
Давайте будем гением компьютера.