简体   繁体   中英

Deduce template parameter pack from function call

I have the following code, where I have a template class, and a type in it, which I would like to use in a separate template function.

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

I tought that the compiler will be able to deduce the parameter pack from the function call, so I can use it in the function template also. Unfortunately the compiler can't deduce it:

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

Is there a solution to "transfer" the template parameter pack to the template function?

Template arguments cannot be deduced from nested types. This isn't new or changed with variadic templates.

Template deduction is not possible, but maybe you can restructure your code in a way that MyClass defines the all necessary types and then you have a check function that takes MyClass as a template argument. That way, the checking function has access to all the necessary types.

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

The downside is of course, that you have to instantiate the checker class or call the function with the proper type of MyClass as template argument.

The template parameter pack can be passed over using std::tuple. A wrapper class needed over SomeEnum type to store the parameter pack by creating a tuple type from them:

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

Than a helper class needed which feeds the template argument list of a template class from the tuple types:

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

The check function then uses this helper class to instanciate the other class:

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

And the use of check function changes a bit becouse now it waits the wrapper type instead of the pure enum:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM