2015-05-17 2 views
4

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

template <typename... Types> 
struct MyClass 
{ 
    enum SomeEnum { value0 = -1 }; 
}; 

template <typename... Types> 
struct OtherClass 
{ 
}; 

template <typename T, typename... Types> 
T check(typename MyClass<Types...>::SomeEnum value) 
{ 
    OtherClass<Types...> obj; 
    T result; 
    // calculate result from obj; 
    return result; 
} 

int main() { 
    auto value = MyClass<int, bool>::value0; 
    // ... 
    int t = check<int>(value); 
} 

Я учил, что компилятор сможет вывести параметр пакет из вызова функции, так что я могу использовать его в шаблоне функции также. К сожалению, компилятор не может вывести его:

$ г ++ -std = C++ 11 op.cpp

op.cpp: In function ‘int main()’: 
op.cpp:25:27: error: cannot convert ‘MyClass<int, bool>::SomeEnum’ to ‘MyClass<>::SomeEnum’ for argument ‘1’ to ‘T check(typename MyClass<Types ...>::SomeEnum) [with T = int; Types = {}; typename MyClass<Types ...>::SomeEnum = MyClass<>::SomeEnum]’ 
    int t = check<int>(value); 

Есть ли решение для «передачи» параметр пакета шаблона функции шаблона?

ответ

1

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

template <typename... Types> struct OtherClass {}; 

template <typename... Types> 
struct MyClass 
{ 
    typedef OtherClass<Types...> OtherClass_t; 
    typedef int result_t; 

    enum SomeEnum { value0 = -1 }; 
}; 

// version 1 
template < typename C > 
struct Checker { 
    typename C::result_t operator()(typename C::SomeEnum value) 
    { 
     typename C::OtherClass_t obj; 
     typename C::result_t result; 
     // calculate result from obj; 
     return result; 
    } 
}; 

// version 2 
template < typename C > 
typename C::result_t check_fun(typename C::SomeEnum value) 
{ 
    typename C::OtherClass_t obj; 
    typename C::result_t result; 
    // calculate result from obj; 
    return result; 
} 


int main() { 
    typedef MyClass< int, bool > myclass_t; 
    auto value = myclass_t::value0; 
    // ... 
    Checker<myclass_t> check; 
    int t = check(value); 
    auto s = check_fun<myclass_t>(value); 
} 

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

+0

Спасибо, это хорошая идея, к сожалению, в самом коде я должен держать оба класса независимыми. – simon

+0

Хотя я разработал решение с использованием кортежей, я собираюсь принять этот ответ, потому что вместо этого я решил перестроить свой код. – simon

1

Аргументы шаблона не могут быть выведены из вложенных типов. Это не ново или не изменено с помощью вариативных шаблонов.

+0

Итак, ваш ответ заключается в том, что нет решения? – simon

+0

@simon: правильный. Из 'value' в отдельности не существует способа определить, откуда оно взялось. –

0

Пакет параметров шаблона можно передать с помощью std :: tuple. Класс обертки требуется более типа SomeEnum хранить пакет параметров, создавая тип кортежа из них:

template <typename... Types> 
struct MyClass 
{ 
    struct Value { 
     enum SomeEnum { value0 = -1 }; 
     enum SomeEnum value; 
     typedef std::tuple<Types...> TypeTuple; 
    }; 
}; 

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

template < 
    template <typename...> class Class, 
    typename Tuple, typename T, T... nums> 
struct Helper_ : Class < 
    typename std::tuple_element<nums, Tuple>::type... > 
{}; 

template <template <typename...> class Class, typename Tuple> 
struct Helper : Helper_< 
    Class, Tuple, 
    make_integer_sequence<int, std::tuple_size<Tuple>::value > > 
{}; 

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

template <typename T, typename V> 
T check(V value) 
{ 
    Helper<OtherClass, typename V::TypeTuple> obj; 
    T result; 
    // calculate result from obj; 
    return result; 
} 

и использование проверки функции изменяет немного becouse теперь я t ожидает тип обертки вместо чистого перечисления:

int main() { 
    MyClass<int, bool, double>::Value value; 
    value.value = MyClass<int, bool, double>::Value::value0; 

    int t = check<int>(value); 
}