I have the template class Foo:
template<class T>
class Foo {
public:
Foo() = default;
Foo(const Foo&) = default;
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
Foo& operator=(const Foo&) = default;
template<class U, typename = typename std::enable_if<
!std::is_same<typename std::decay<U>::type, Foo>::value>::type>
Foo(U&&) {
}
};
int main() {
Foo<int> ff;
Foo<char> dd(ff); //here I want a compiler error
Foo<int> e(15); //it should work
return 0;
}
I'm trying to add constraints about template constructor, however this code compiles so I think I'm missing something, what's the proper way to add the enable_if?
CodePudding user response:
In your main()
function, you're trying to construct a Foo<char>
from a Foo<int>
. A decay-based ctor will not work here, as Foo<A>
does not decay into Fooeven if
Adecays into
B. See [the cppreference page on
std::decay`]1 for a detailed explanation of what it does, exactly.
Also, I would suggest avoiding explicit (templated) constructors from pre-decay types. If your argument too one of the copy or move constructors (from const Foo&
and Foo&&
respectively) decays into a Foo
, then those ctors should be enough. And if they somehow aren't, this implicit conversion that you're allowing for is probably more trouble than it's worth. It will certainly make your class more difficult to read and to adapt. You have, in fact, already seen it has led you to a minor bug :-P
CodePudding user response:
Besides the typo, you can also make use of the deleted function declaration as shown below:
#include <iostream>
#include <type_traits>
template<class T>
class Foo {
public:
Foo() = default;
Foo(const Foo&) = default;
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
Foo& operator=(const Foo&) = default;
template<typename K, typename = typename std::enable_if_t<!std::is_same_v<T, K>>>
Foo (Foo<K> const&) = delete;
};
int main() {
Foo<int> ff;
Foo<int> gg(ff); //THIS WORKS
//Foo<char> dd(ff); //THIS PRODUCES ERROR
return 0;
}