Home > other >  Priority of template constructor
Priority of template constructor

Time:03-27

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 ifAdecays intoB. 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;
}

Demo

  • Related