Проблема с реализацией признаков на основе SFINAE с перегрузкой шаблона функции - PullRequest
0 голосов
/ 28 мая 2020

Я изучаю SFINAE и трейты, и я знаю, что могу определять черты, связанные с SFINAE (трейты, которые используют SFINAE в своей реализации). Классическая реализация c признака, которая определяет, является ли тип конструктивным по умолчанию:

template <typename T>
struct IsDefaultConstructibleH
{
private:
    template <typename U, typename = decltype(U())>
    //template <typename U, const U& = U()>   // WHY IS THIS ALWAYS SFINAE'd out?
    static TrueType Test(void*);
    template <typename>
    static FalseType Test(...);
public:
    using Type = decltype(Test<T>(nullptr));
};

template <typename T>
struct IsDefaultConstructible : IsDefaultConstructibleH<T>::Type
{
};

template <typename T>
constexpr bool IsDefaultConstructibleV = IsDefaultConstructible<T>::Value;

Как я указал в приведенном выше коде, если я использую закомментированное предложение параметризации шаблона (и комментарий -из вышеприведенного), если я запустил этот код:

#include "traits.hpp"
#include <iostream>

class Default
{
public:
    Default() : mData(10) {}
private:
    int mData;
};

class NoDefault
{
public:
    NoDefault(int i) : mData(i) {}
private:
    int mData;
};

int main(int argc, char ** argv)
{
    std::cout << std::boolalpha << IsDefaultConstructible<Default>::Value << std::endl;
    std::cout << std::boolalpha << IsDefaultConstructibleV<NoDefault> << std::endl;

    return 0;
}

, результат всегда будет false false, тогда как если я использую другое предложение параметризации (то, которое не закомментировано), программа дает истина, ложь, как и ожидалось. Так почему же в предложении с параметром, не являющимся типом, всегда выводится SFINAE?

1 Ответ

2 голосов
/ 28 мая 2020

Типы ссылок как параметры шаблона, не являющиеся типами должно быть именем объекта со связью (обычно это глобальная переменная). См. https://en.cppreference.com/w/cpp/language/template_parameters#Template_non -тип_аргументов . В частности, он не может быть временным.

Таким образом, const U& = U() всегда недопустимо в шаблоне, поскольку U() не является именем переменной (оно должно выглядеть как const U& = some_global_U_variable), поэтому не будет выбирается в Test<T>(nullptr).

...