【问题标题】:Deduce template parameter pack from function call从函数调用中推导出模板参数包
【发布时间】:2015-05-17 17:21:50
【问题描述】:

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

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

有没有办法将模板参数包“转移”到模板函数中?

【问题讨论】:

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


    【解决方案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】:

    模板参数不能从嵌套类型推导出来。这不是新的,也不是通过可变参数模板改变的。

    【讨论】:

    • 所以你的回答是没有解决办法?
    • @simon:正确。仅从value 无法确定它的来源。
    【解决方案3】:

    可以使用 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 > > 
    {};
    

    然后检查函数使用这个帮助类来实例化另一个类:

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

    【讨论】:

      猜你喜欢
      • 2015-09-19
      • 1970-01-01
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 2018-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多