Как мне включить_if вариативный шаблонный шаблон, только если задано более n аргументов? - PullRequest
0 голосов
/ 25 января 2019

У меня есть класс со следующими конструкторами:

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;
};

Я также хочу создать конструктор, который принимает произвольное количество аргументов (каждый из которых может быть T). Конструктор также не должен скрывать других конструкторов, которые я уже написал, так как проделанная работа отличается. Я немного попробовал с enable_if, но не могу заставить это работать. Вот что у меня есть:

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

Однако при вызове так:

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

выдает эту ошибку (среди прочих):

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

Так что компилятор, вероятно, даже не видит конструктор. С другой стороны, если я просто опущу enable_if, он никогда не вызовет мои другие, более специализированные конструкторы.

Короче говоря, как мне сделать так, чтобы конструктор с переменными координатами назывался тогда и только тогда, когда есть три или более аргумента, заданных конструктору?

EDIT:

Как предложено в комментариях, я также попробовал следующее, которое также не работает:

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

а также

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

или любое их сочетание.

1 Ответ

0 голосов
/ 25 января 2019

Предложение: попробуйте использовать

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

или лучше (чтобы избежать коллизий с несколькими конструкторами с поддержкой SFINAE с одинаковой подписью).

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

Проблема с исходным кодом

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

заключается в том, что вы можете вывести список типов переменных только в том случае, если относительные аргументы находятся в последней позиции.

Если вы добавите еще один аргумент

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

, вы нарушитевычет для TArgs... типов.

...