0xbadf00d
0xbadf00d

Reputation: 18178

How should I conditionally enable a constructor?

I'm trying to achieve something like this:

template<typename Bar>
class foo
{
public:
    template<class = std::enable_if_t<std::is_constructible<Bar, int>::value>>
    foo(int x)
        : m_bar(x)
    { }

private:
    Bar m_bar;
};

This yields the behavior

foo<int> a; // no error
foo<int> b(0); // no error
foo<std::string> c; // no error
foo<std::string> d(0); // error: none of the 3 overloads could convert all the argument types

as expected. Is there any disadvantage of this solution? What I don't like is that in either case foo::foo(int) exists. I know that I could use the enable_if in the template parameter list of foo itself and specialize foo for the two cases, but I don't want to duplicate the common code.

So, is this the best (or at least a sensible) option?

Upvotes: 0

Views: 806

Answers (1)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48447

Is there any disadvantage of this solution?

Currently, the substitution takes place outside of an immediate context, so your approach will cause a hard compilation error as soon as you attempt to instantiate foo with a type that is not constructible with an int.

To introduce an immediate context, you'd need a dummy parameter:

template <typename T = Bar
//                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~v
        , typename = std::enable_if_t<std::is_constructible<T, int>::value>>
foo(int x)
    : m_bar(x)
{ }

DEMO

Upvotes: 3

Related Questions