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

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

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

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

Это мой код:

#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 из аргументов функции компилятор жалуется на недопустимые перегрузки (конечно)

Есть ли элегантный способ решить эту проблему?

Редактировать:
Одно неявное преобразование, разрешенное стандартом, не должно происходить в моем классе. [пример кода отредактирован]

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

(Не стесняйтесь редактировать вопрос, если что-то можно сделать более понятным)

12

Решение

Я не могу понять проблему, а также решение. Если я хочу использовать 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
2

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

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

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