Статические утверждения и SFINAE

Учти это:

template <typename T>
struct hash
{
static_assert(false,"Not implemented.");
};

struct unhashable {};

template <typename T>
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int);

void test(...);

int main()
{
std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value;
}

Помимо явно отсутствующих заголовков, этот компилятор должен?

Другими словами, я спрашиваю, запрашивается ли сбой статического утверждения внутри конечного типа decl при выводе возвращаемого значения перегруженного шаблона функции, чтобы остановить компиляцию, или перегрузку просто нужно отбросить.

На gcc 4.7 компиляция не удалась. Я довольно уверен, что это скомпилируется нормально в gcc 4.8 (но не может проверить в данный момент). Кто прав?

9

Решение

Компиляция должна завершиться неудачей в любом совместимом компиляторе.

Правила SFINAE основаны на декларациях, а не на определениях. (Извините, если я здесь использую неправильную терминологию.) Я имею в виду следующее:

Для класса / структуры:

template < /* substitution failures here are not errors */ >
struct my_struct {
// Substitution failures here are errors.
};

Для функции:

template </* substitution failures here are not errors */>
/* substitution failures here are not errors */
my_function( /* substitution failures here are not errors */) {
/* substitution failures here are errors */
}

Кроме того, несуществование структуры / функции для данного набора аргументов шаблона также подчиняется правилам SFINAE.

Сейчас static_assert может появляться только в тех регионах, где сбои подстановки являются ошибками, и, следовательно, если она сработает, вы получите ошибку компилятора.

Например, следующее будет неправильной реализацией enable_if:

// Primary template (OK)
template <bool, typename T>
struct enable_if;

// Specialization for true (also OK)
template <typename T>
struct enable_if<true, T> {
using type = T;
};

// Specialization for false (Wrong!)
template <typename T>
struct enable_if<false, T> {
static_assert(std::is_same<T, T*>::value, "No SFINAE here");
// The condition is always false.
// Notice also that the condition depends on T but it doesn't make any difference.
};

Тогда попробуй это

template <typename T>
typename enable_if<std::is_integral<T>::value, int>::type
test(const T &t);

void test(...);

int main()
{
std::cout << std::is_same<decltype(test(0)), int>::value << std::endl; // OK
std::cout << std::is_same<decltype(test(0.0)), void>::value << std::endl; // Error: No SFINAE Here
}

Если вы удалите специализацию enable_if за false затем код компилируется и выводится

1
1
12

Другие решения

На gcc 4.7 компиляция не удалась. Я довольно уверен, что это скомпилируется нормально в gcc 4.8 (но не может проверить в данный момент). Кто прав?

Условие в вашем статическом утверждении не зависит ни от одного параметра шаблона. Таким образом, компилятор может сразу оценить его false при синтаксическом анализе шаблона и осознайте, что утверждение должно срабатывать — независимо от того, действительно ли вы создали экземпляр шаблона где-либо еще.

То же самое должно быть верно для любого компилятора.

6

По вопросам рекламы [email protected]