& Quot; Перегрузка & Quot; конструкторы с SFINAE

Почему следующее попытка при перегрузке конструктора Foo::Foo потерпеть поражение? Кроме того, я был бы признателен за альтернативы / обходные пути

#include <vector>
#include <type_traits>

namespace xyz
{
struct MemoryManager{};

template<typename T , typename Alloc=MemoryManager>
class vector
{
};
}template<typename T, template<typename,typename> class V , typename A>
struct Foo
{
template<typename U = T ,
typename Dummy = typename std::enable_if<
std::is_same<std::vector<U>, V<U,A> >::value >::type >
Foo() // when instantiated with the std vector
{
}

template<typename U = T ,
typename Dummy = typename std::enable_if<
std::is_same<xyz::vector<U>, V<U,A> >::value >::type >
Foo() // when instantiated with my custom vector
{
}
};

int main()
{
}

Сообщение об ошибке:

23:3: error: ‘template<class T, template<class, class> class V, class A> template<class U, class Dummy> Foo<T, V, A>::Foo()’ cannot be overloaded
Foo() // when instantiated with my custom vector

18:3: error: with ‘template<class T, template<class, class> class V, class A> template<class U, class Dummy> Foo<T, V, A>::Foo()’
Foo() // when instantiated with the std vector

3

Решение

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

template <typename, typename>
Foo();

template <typename, typename>
Foo();

Это правило может быть яснее за пределами мира шаблонов, где эти две функции не могут перегружать друг друга:

void foo(int x = 42);
void foo(int y = 17);

Вместо этого вы можете сделать 2-й аргумент шаблона дефолтным не типа параметр, так что два конструктора имеют разные подписи:

template<typename U = T ,
std::enable_if_t<std::is_same<std::vector<U> , V<T,A> >::value, int> = 0>
Foo() // when instantiated with the std vector

Или вы можете делегировать оба конструктора, используя фиктивный тип:

template <typename T> struct tag { };

Foo()
: Foo(tag<V<T,A>>{})
{ }

Foo(tag<std::vector<T>> )
{ /* std vector */ }

Foo(tag<xyz::vector<T>> )
{ /* your vector */ }
7

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