从函数调用中减去模板参数包

时间:2015-05-17 17:21:50

标签: c++ templates c++11 variadic

我有以下代码,其中有一个模板类和一个类型,我想在一个单独的模板函数中使用它。

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);
}

我认为编译器能够从函数调用中推导出参数包,所以我也可以在函数模板中使用它。不幸的是,编译器无法推断它:

$ g ++ -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);

是否有解决方案将模板参数包“转移”到模板功能?

3 个答案:

答案 0 :(得分:1)

无法从嵌套类型推断出模板参数。这不是新的或使用可变参数模板进行更改。

答案 1 :(得分: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作为模板参数调用该函数。

答案 2 :(得分:0)

可以使用std :: tuple传递模板参数包。 SomeEnum类型需要一个包装类来通过从它们创建元组类型来存储参数包:

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

需要一个帮助类,它从元组类型中提供模板类的模板参数列表:

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 > > 
{};

check函数然后使用这个帮助器类来实现另一个类:

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

并且检查函数的使用有点变化,因为它现在等待包装类型而不是纯枚举:

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

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