Специализация шаблона с enable_if не работает в Clang, работает с GCC - PullRequest
0 голосов
/ 11 февраля 2019

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

Я попробовал следующий код, который компилируется с GCC (9.0.1), но выдает ошибкув Clang (9.0.0).Я думаю, что также не удается построить код в MSVC ++.

#include <type_traits>
#include <iostream>

template <typename T>
struct my_type {
    template <typename Q = T>
    std::enable_if_t<!std::is_same<bool, Q>::value, my_type<T>> my_fun(const my_type<T>& v) {
        std::cout << "Base";
        return v;
    }
};

template <>
template <typename Q> 
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>> my_type<double>::my_fun(const my_type<double>& v) {
    std::cout << "Specialized";
    return v;
}


int main()
{
    my_type<double> aa, bb;
    aa.my_fun(bb);
}

Ошибка с Clang:

prog.cc:16:88: error: out-of-line definition of 'my_fun' does not match any declaration in 'my_type<double>'
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>> my_type<double>::my_fun(const my_type<double>& v) {
                                                                                       ^~~~~~
1 error generated.

Я хотел бы знать, как заставить код работать, а также, почему результаты не согласованы между всеми основными компиляторами.

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

В обоих случаях: my_type специализируется на double.Затем сравните неспециализированную версию my_fun

template < >
template <typename Q> 
std::enable_if_t<!std::is_same_v<bool, Q>::value, my_type<double>>
//                                     ^ (!)
my_type<double>::my_fun(const my_type<double>& v)

с полностью специализированной my_fun:

template < >
template < >
//        ^
std::enable_if_t<!std::is_same<bool, double>::value, my_type<double>>
my_type<double>::my_fun<double>(const my_type<double>& v)
//                        ^

Оба приведенных выше варианта будут допустимы;вы, напротив, оказались где-то посередине ...

GCC, принимающий этот код, мне не подходит, я присоединяюсь к фракции "это ошибка" в комментариях.

Возможно, даже хуже: рассмотрите специализацию my_type<double>::my_fun<bool> - она ​​должна существовать, не так ли?

0 голосов
/ 11 февраля 2019

Вы не можете использовать enable_if здесь для подавления функции-члена в зависимости от параметра шаблона класса, т.е. T (но только в зависимости от параметра шаблона функции, то есть Q.

Ваш код неверен, как справедливо указывает clang. Я не знаю, почему gcc принимает его и как он может определить, что Q относится к вашей «специализации» (я считаю, ваш код, скомпилированный с помощью gccуказано «Base» - правильно? Кроме того, поскольку нет наследования, неясно, почему вы используете "Base".)

без типа тега, вы можете сделать следующее.

template <typename T>
struct my_type {
  private:
    template<bool Standard>
    std::enable_if_t<Base, my_type> my_fun_impl(const my_type& v)
    {
        std::cout << "Standard";
        return v;
    }
    template<bool Standard>
    std::enable_if_t<!Standard, my_type> my_fun_impl(const my_type& v)
    {
        std::cout << "Specialised";
        return v;
    }
  public:
    my_type my_fun(const my_type& v)
    {
        return my_fun_impl<is_standard<T>::value>(v);
    }
};

за то, что is_standard<> вы хотите.

0 голосов
/ 11 февраля 2019

Я не знаю, как заставить это работать со специализацией.Но я знаю, как полностью обойти проблему:

template <typename> struct tag { };

template <typename Q = T>
std::enable_if_t<!std::is_same_v<bool, Q>, my_type<T>> my_fun(const my_type<T>& v) {
    return my_fun_impl(v, tag<Q>{});
}

с помощью:

template <typename U>
my_type my_fun_impl(const my_type& v, tag<U>) {
    std::cout << "Base";
    return v;
}

my_type my_fun_impl(const my_type& v, tag<double>) {
    std::cout << "Specialized";
    return v;
}

Если вы хотите, чтобы специализация дала пользователям возможность добавлять специализированные реализации, вы могли бысделать my_fun_impl свободной функцией вместо функции-члена.Если цель состояла в том, чтобы просто специализироваться на определенных типах, вы можете сделать их частными функциями-членами.

...