Неоднозначность с вариационными шаблонами

У меня есть вопрос по поводу шаблонов вариа У меня есть класс, который использует их следующим образом:

template <class... T>
struct A {
A(B& arg);                   // (1)
A(typename T::B& args...);   // (2)
};

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

Определение конструкторов не очень важно для моей проблемы, вы можете оставить их пустыми. Более полный пример приведен ниже.

Теперь проблема в том, что конструкторы конфликтуют, если вы инициализируете A только одним параметром. g++-4.7 был немного смущен и выручил, но после более пристального взгляда на класс проблема была очевидна.

Вопросы:

  1. Что стандарт говорит о ситуации? Это неоднозначность, которая должна / может быть решена компилятором, или я должен избежать этой ситуации?

  2. Каковы лучшие стратегии, чтобы избежать этого? Не указываете что-то вроде первого конструктора вообще? Я также мог бы поместить функциональность первого конструктора в статический метод, но это сделало бы API более неоднородным.

Спасибо за ваши ответы!


Полный пример:

struct B {};

struct C
{
using B = ::B;
};

template <class... T>
struct A
{
A(B& arg) {}
A(typename T::B & ... args) {}
};

int main()
{
A<C> x(B()); // Edit: Should be: A<C> X{B()}; But not related to the problem.
return 0;
}

0

Решение

A<C> x(B());

Объявление функции, а не объявление объекта. Вам нужно добавить парены или использовать фигурные скобки:

A<C> x { B() };

или же

A<C> x((B()));

Также пройти временный B к конструктору по ссылке, вы должны сделать это const:

A(const B& arg) { }

затем

A<C> x((B()));

Работает отлично.

Теперь, чтобы решить проблему неоднозначности, вам нужно что-то вроде этого:

#include <type_traits>
#include <iostream>

struct B {};

struct C
{
using B = ::B;
};

template <class... T>
struct A
{
A(const B& arg) {
std::cout << "one" << std::endl;
}

template<bool IsNotOne = sizeof...(T) != 1>
A(const typename std::enable_if<IsNotOne || !std::is_same<B, T>::value, T>::type::B&... args) {
std::cout << "multiple" << std::endl;
}
};

int main()
{
A<B> x1 { B() };         // prints one
A<C> x2 { B() };         // prints one
A<C, C> x3 { B(), B() }; // prints multiple
A<B, B> x4 { B(), B() }; // prints multiple
return 0;
}

Мы делаем второй конструктор шаблоном, чтобы мы могли положиться на SFINAE.

4

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector