У меня есть вопрос по поводу шаблонов вариа У меня есть класс, который использует их следующим образом:
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
был немного смущен и выручил, но после более пристального взгляда на класс проблема была очевидна.
Вопросы:
Что стандарт говорит о ситуации? Это неоднозначность, которая должна / может быть решена компилятором, или я должен избежать этой ситуации?
Каковы лучшие стратегии, чтобы избежать этого? Не указываете что-то вроде первого конструктора вообще? Я также мог бы поместить функциональность первого конструктора в статический метод, но это сделало бы 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;
}
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.
Других решений пока нет …