简体   繁体   中英

How do I enable_if a variadic template constructor only if more than n arguments are given?

I have a class with the following constructors:

template<typename T>
class MyClass {
public:
    MyClass() = default;
    explicit MyClass(T val) : value_1(val) { /* ... */ }
    explicit MyClass(T val, T val2) : value_1(val), value_2(val2) { /* ... */}

private:
    T value_1 = 0;
    T value_2 = 0;
};

I also want to create a constructor that takes an arbitrary number of arguments (all of which can be T 's). The constructor also mustn't shadow the other constructors I already wrote, as the work done is different. I tried around with enable_if a little bit, but am unable to get this to work. Here is what I have so far:

template<typename... TArgs>
explicit MyClass(TArgs... mArgs, typename std::enable_if<sizeof...(mArgs) >= 3>) { /* ... */ }

However, when called like this:

MyClass<double>(2, 3, 4, 5, 6, 7);

it yields this error (among others):

error: no matching function for call to 'MyClass<double>::MyClass(int, int, int, int, int, int)'

So the compiler probably doesn't even see the constructor. On the other hand if I just leave out the enable_if , it will never call my other, more specialized constructors.

In short, how do I make it so the variadic constructor is called if and only if there are three or more arguments given to the constructor?

EDIT:

As proposed in the comments, I have now also tried the following, which also does not work:

template<typename... TArgs>
explicit MyClass(TArgs... mArgs, typename std::enable_if<sizeof...(mArgs) >= 3>::type) { /* ... */ }

as well as

template<typename... TArgs>
explicit MyClass(TArgs... mArgs, typename std::enable_if<sizeof...(mArgs) >= 3>* = nullptr) { /* ... */ }

or any combination of the two.

Suggestion: try with

template <typename... TArgs,
          typename = typename std::enable_if<sizeof...(TArgs) >= 3>::type>
explicit MyClass(TArgs... mArgs) { /* ... */ }

or better (to avoid collisions with multiple SFINAE enabled constructors with the same signature).

template <typename... TArgs,
          typename std::enable_if<sizeof...(TArgs) >= 3, bool>::type = true>
explicit MyClass(TArgs... mArgs) { /* ... */ }

The problem with your original code

template<typename... TArgs>
explicit MyClass(TArgs... mArgs, typename std::enable_if<sizeof...(mArgs) >= 3>::type) { /* ... */ }

is that you can deduce a variadic list of types only if the relative arguments are in last position.

If you add another argument

typename std::enable_if<sizeof...(mArgs) >= 3>::type

you break the deduction for the TArgs... types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM