2012-01-09 5 views
1

Я хотел бы иметь возможность построить A или B, не задумываясь о количестве аргументов конструктора.Как написать шаблон, который может решить, какой конструктор вызвать?

Второй конструктор не является законным C++, но я написал это как попытку выразить то, что я хочу.

Есть ли опция enable_if для выборочного включения одного из конструкторов?

(например, в зависимости от количества конструктора аргументов А и В.)

мне это нужно, чтобы проверить около 15 классов с 1, 2 или 3 аргументов конструктора.

struct A 
{ 
    A(int x) 
    { 
    } 
}; 

struct B 
{ 
    B(int x, int y) 
    { 
    } 
}; 

template<typename T> 
struct Adaptor // second constructor is illegal C++. 
{ 
    T t; 

    Adaptor(int x, int y) 
     : t(x) 
    { 
    } 

    Adaptor(int x, int y) // error: cannot be overloaded 
     : t(x, y) 
    { 
    } 
}; 

int main() 
{ 
    Adaptor<A> a(1,2); 
    Adaptor<B> b(1,2); 

    return 0; 
} 
+0

Почему бы просто не назвать 'A :: A' с одним аргументом, и' B :: B 'с двумя аргументами? –

+2

Зачем вам нужно писать «Адаптер a (1,2)», если «2» просто нужно отбросить? – ruakh

+0

Я хочу дать A и B тот же интерфейс, обернув их. –

ответ

6

Вариант @ подхода Ааронова:

#include <type_traits> 
#include <utility> 

enum EArity { EZero = 0, EOne, ETwo, EThree, Error }; 

template <typename T, typename A1, typename A2, typename A3> struct getArity 
{ 
    static const EArity arity = 
     std::is_constructible<T>::value    ? EZero : 
     std::is_constructible<T, A1>::value   ? EOne : 
     std::is_constructible<T, A1, A2>::value  ? ETwo : 
     std::is_constructible<T, A1, A2, A3>::value ? EThree : Error; 
}; 

template <typename T, EArity A> struct Construct; 

template <typename T> struct Construct<T, EZero> 
{ 
    T t; 

    template <typename A1, typename A2, typename A3> 
    Construct(A1 && a1, A2 && a2, A3 && a3) : t() { } 
}; 

template <typename T> struct Construct<T, EOne> 
{ 
    T t; 

    template <typename A1, typename A2, typename A3> 
    Construct(A1 && a1, A2 && a2, A3 && a3) : t(std::forward<A1>(a1)) { } 
}; 

// ... 

template <typename T> 
struct AdapterIntIntInt : Construct<T, getArity<T, int, int, int>::arity> 
{ 
    Adapter(int a, int b, int c) 
    : Construct<T, getArity<T, int, int, int>::arity>(a, b, c) { } 
}; 

template <typename T, typename A1, typename A2, typename A3> 
struct Adapter : Construct<T, getArity<T, A1, A2, A3>::arity> 
{ 
    Adapter(A1 && a1, A2 && a2, A3 && a3) 
    : Construct<T, getArity<T, A1, A2, A3>::arity> 
     (std::forward<A1>(a1), std::forward<A2>(a2), std::forward<A3>(a3)) 
    { } 
}; 
+0

Вы знаете, какие компиляторы поддерживают 'is_constructible'? –

+0

@DavidBrown: Нет, не боюсь :-) –

+0

Не знаете, насколько это полезно, но вот какой-то код для подсчета количества аргументов в конструкторе. Зависит от typeof, хотя - только g ++, не так ли? http://ideone.com/y0Ich –

1

Использовать шаблон специализации. Первым адаптером является шаблон по умолчанию, но последний будет использоваться только для Adaptor<A>.

template<typename T> 
struct Adaptor 
{ 
    T t; 

    Adaptor(int x, int y) 
     : t(x,y) 
    { 
    } 


}; 

template<> 
struct Adaptor<A> { 
    A t; 
    Adaptor(int x, int y) 
     : t(x) 
    { 
    } 
}; 
+0

Да, но у меня есть 15 классов, которые я хочу обернуть, но я не хочу писать 15 специализаций, только 3, потому что единственное отличие состоит в 1, 2 или 3 аргументах. –

2

Другой вариант:

#include <boost/utility/enable_if.hpp> 

struct A { 
    A(int) {} 
}; 

struct B { 
    B(int, int) {} 
}; 

template <class T> 
struct arg_count { 
}; 

template <> 
struct arg_count<A> { 
    const static int count = 1; 
}; 

template <> 
struct arg_count<B> { 
    const static int count = 2; 
}; 

template <class T> 
struct Adaptor : public T { 
    template <class A1, class A2> 
    Adaptor(A1 a1, A2 a2, typename boost::enable_if_c<arg_count<T>::count == 1, A1>::type* = 0) : T(a1) {} 

    template <class A1, class A2> 
    Adaptor(A1 a1, A2 a2, typename boost::enable_if_c<arg_count<T>::count == 2, A2>::type* = 0) : T(a1, a2) {} 
}; 


int main() { 
    Adaptor<A> a(1, 2); 
    Adaptor<B> b(1, 2); 
} 
+0

Мне нравится это лучше, чем другое решение для специализированного шаблона, поскольку оно отделяет часть arg_count. Это, вероятно, лучшее решение для C++ 03. –

+0

Что означает 'A1' как второй аргумент' enable_if_c'? –

+0

Параметр шаблона A1 является типом, который enable_if_c :: type дает, когда условие истинно. Значение по умолчанию недействительно. –

Смежные вопросы