У меня есть этот код, который работает, как и ожидалось, с GCC 9.1:
#include <type_traits>
template< typename T >
class A
{
protected:
T value;
public:
template< typename U,
typename...,
typename = std::enable_if_t< std::is_fundamental< U >::value > >
A& operator=(U v)
{
value = v;
return *this;
}
};
template< typename T >
class B : public A<T>
{
public:
using A<T>::operator=;
template< typename U,
typename...,
typename = std::enable_if_t< ! std::is_fundamental< U >::value > >
B& operator=(U v)
{
this->value = v;
return *this;
}
};
int main()
{
B<int> obj;
obj = 2;
}
(На практике мы сделали бы что-нибудь необычное в B::operator=
и даже использовали бы другие черты типа для enable_if
, но это самый простой воспроизводимый пример.)
Проблема в том, что Clang 8.0.1 выдает ошибку, почему-то не учитывается operator=
от родительского класса, хотя у дочернего есть using A<T>::operator=;
:
test.cpp:39:9: error: no viable overloaded '='
obj = 2;
~~~ ^ ~
test.cpp:4:7: note: candidate function (the implicit copy assignment operator) not viable:
no known conversion from 'int' to 'const A<int>' for 1st argument
class A
^
test.cpp:4:7: note: candidate function (the implicit move assignment operator) not viable:
no known conversion from 'int' to 'A<int>' for 1st argument
class A
^
test.cpp:20:7: note: candidate function (the implicit copy assignment operator) not
viable: no known conversion from 'int' to 'const B<int>' for 1st argument
class B : public A<T>
^
test.cpp:20:7: note: candidate function (the implicit move assignment operator) not
viable: no known conversion from 'int' to 'B<int>' for 1st argument
class B : public A<T>
^
test.cpp:28:8: note: candidate template ignored: requirement
'!std::is_fundamental<int>::value' was not satisfied [with U = int, $1 = <>]
B& operator=(U v)
^
1 error generated.
Какой компилятор соответствует стандарту? (Я компилирую с -std=c++14
.) Как мне изменить код, чтобы он стал правильным?
operator=
не может иметь аргумента по умолчанию. - person L. F.   schedule 02.08.2019typename...
? Они всегда выводятся как пустые, так почему? - person L. F.   schedule 02.08.2019typename...
запрещает пользователям обходить SFINAE с помощью чего-то вродеobj.template operator=<int, foo>(2)
. Я признаю, что это более полезно для обычных функций, чем для операторов, и здесь не имеет значения. - person Jakub Klinkovský   schedule 02.08.2019std::enable_if_t<..., int> = 0
вместо этого. - person L. F.   schedule 02.08.2019std::enable_if_t<cond<T>::value, int> = 0>
(по сравнению сtypename = std::enable_if_t<cond<T>::value>
) также позволит избежать захвата (и, кроме того, позволит перегрузить) - person Jarod42   schedule 02.08.2019template <typename T, std::enable_if_t<my_condition, bool> = true> return_type function_name(params)
. Это позволяет вам писать наборы перегрузки, такие какtemplate <typename T, std::enable_if_t<std::is_intergral_v<T>, bool> = true> return_type function_name(params)
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> return_type function_name(params)
, поскольку значения шаблона по умолчанию являются частью подписи шаблона. - person NathanOliver   schedule 02.08.2019std::enable_if_t
в двух разных местах, если вы хотите написать определение функции-члена вне объявления класса? - person Jakub Klinkovský   schedule 02.08.2019