Что такое decltype с двумя аргументами?
Изменить, чтобы избежать путаницы: decltype
не принимает два аргумента. См. Ответы.
Следующие две структуры могут использоваться для проверки существования функции-члена в типе T
во время компиляции:
// Non-templated helper struct:
struct _test_has_foo {
template<class T>
static auto test(T* p) -> decltype(p->foo(), std::true_type());
template<class>
static auto test(...) -> std::false_type;
};
// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};
Я думаю, что идея заключается в использовании SFINAE при проверке существования функции-члена, поэтому в случае, если p->foo()
недействителен, определена только версия эллипсов test
, которая возвращает std::false_type
. В противном случае первый метод будет определен для T*
и вернет std::true_type
. Фактический "переключатель" происходит во втором классе, который наследуется от типа, возвращаемого test
. Это кажется умным и "легким" по сравнению с разными подходами с is_same
и тому подобным.
decltype
с двумя аргументами сначала выглядел удивительно для меня, так как я думал, что он просто получает тип выражения. Когда я увидел код выше, я подумал, что это похоже на "попытаться скомпилировать выражения и всегда возвращать тип второго. Сбой, если выражения не скомпилируются" (так что скрыть эту специализацию: SFINAE).
Но:
Затем я подумал, что могу использовать этот метод для записи любой проверки "допустимого выражения", если это зависит от некоторого типа T
. Пример:
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
http://ideone.com/dJkLPF
Это, как я думал, вернет a std::true_type
тогда и только тогда, когда определено bar
, принимающее T
в качестве первого параметра (или если T
является конвертируемым и т.д.), то есть: если bar(*p)
будет компилироваться, если он был написан в некотором контексте, где p
определяется типа T*
.
Однако приведенная выше модификация всегда оценивается до std::false_type
. Почему это? Я не хочу исправлять его с помощью некоторого сложного кода. Я просто хочу знать, почему это не работает, как я ожидал. Ясно, что decltype
с двумя аргументами работает не так, как я думал. Я не мог найти никакой документации; это объясняется только одним выражением.
Ответы
Ответ 1
Это список выражений, разделенных запятыми, тип идентичен типу последнего выражения в списке. Он обычно используется для проверки того, что первое выражение является допустимым (компилируемым, думаю, SFINAE), второе используется для указания того, что decltype
должен возвращаться в случае, если первое выражение действительно.
Ответ 2
decltype
не принимает два аргумента. Просто он может иметь выражение как свой аргумент, а оператор запятой - один из способов создания выражений. В пункте 5.18/1:
[...] Пара выражений, разделенных запятой, оценивается слева направо; левое выражение - это отброшенное значение выражения (пункт 5). Каждое вычисление значения и побочный эффект, связанный с левым выражением секвенируется перед вычислением каждого значения и побочным эффектом, связанным с правильным выражением. Тип и значение результата - это тип и значение правого операнда; результат имеет одну и ту же категорию значений как его правый операнд, и является битовым полем, если его правый операнд является glvalue и бит-полем. Если значение права операнд является временным (12.2), результатом является временный.
Таким образом:
static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");