Я пытаюсь создать класс, который должен наследовать конструкторы от других классов, но без наследования от этих классов.
В какой-то момент во время инициализации моего класса я хочу использовать идеальную пересылку для создания объекта типа, конструктор которого соответствует заданным аргументам.
За исключением конструктора по умолчанию без аргументов, не должно быть неоднозначностей.
Это мой код:
#include <string>
using namespace std;
//NOTE: this class is just an example to demonstrate the problem
class String {
public:
//default constructor to prevent ambiguity
String() {}
//construct from wstring
template<typename... Args>
String(enable_if<is_constructible<wstring, Args...>::value, Args>::type&&... args) : ws(forward<Args>(args)...) {}
//construct from string
template<typename... Args>
String(enable_if<is_constructible<string, Args...>::value, Args>::type&&... args) : s(forward<Args>(args)...) {}
private:
string s;
wstring ws;
};
void foo(const String& string) {
}
int main()
{
foo(L"123");
foo("123");
return 0;
}
Я пробовал много вещей, но я просто не могу заставить его работать.
enable_if
не в состоянии автоматически вычитать аргументы шаблона (я думаю)enable_if
на возвращаемое значениеenable_if
не будет работать, потому что конструкторenable_if
из аргументов функции компилятор жалуется на недопустимые перегрузки (конечно)Есть ли элегантный способ решить эту проблему?
Редактировать:
Одно неявное преобразование, разрешенное стандартом, не должно происходить в моем классе. [пример кода отредактирован]
Одно из решений, которое работает с приведенным выше примером, состоит в том, чтобы определить единый конструктор переменных и выполнить перенаправление аргументов в условную функцию инициализации. Тем не менее, я хотел бы избежать этих издержек, потому что члены должны быть созданы по умолчанию, и это может не сработать в других случаях.
(Не стесняйтесь редактировать вопрос, если что-то можно сделать более понятным)
Я не могу понять проблему, а также решение. Если я хочу использовать 2 разных типа для метода или конструктора, я могу просто написать оба типа. По этой причине нет необходимости иметь шаблон с SFINAE! Это может быть просто сделано по специализации.
class A
{
public:
template <typename ... Args>
A(const wstring &, Args ... );
template <typename ... Args>
A(const string &, Args ...);
};
Иметь шаблон, который точно соответствует только одному типу, на самом деле не является семантически шаблоном 🙂
Прочитав ваш комментарий, я получил это решение:
class foo
{
public:
template <typename ... Args>
foo( const string &&x, Args ... ) { cout << "Using string" << endl; }
template <typename ... Args>
foo( const wstring &&x, Args ...) { cout << "Using wstring" << endl; }
};
int main()
{
foo("123");
foo(L"123");
foo("123", 1);
foo(L"123", 1.11);
return 0;
}
и это возвращение, как и ожидалось:
Using string
Using wstring
Using string
Using wstring
Других решений пока нет …