从函数调用推导模板参数包
Deduce template parameter pack from function call
我有以下代码,其中有一个模板 class,其中有一个类型,我想在单独的模板函数中使用它。
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);
有没有解决"transfer"模板参数包到模板函数的方法?
无法从嵌套类型推导模板参数。这不是新的或使用可变参数模板更改的。
模板推导是不可能的,但也许你可以用 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);
}
缺点当然是,您必须实例化检查器 class 或使用 MyClass
的正确类型作为模板参数调用函数。
模板参数包可以使用std::tuple传过来。 SomeEnum 类型需要一个包装器 class 通过从它们创建一个元组类型来存储参数包:
template <typename... Types>
struct MyClass
{
struct Value {
enum SomeEnum { value0 = -1 };
enum SomeEnum value;
typedef std::tuple<Types...> TypeTuple;
};
};
比一个助手 class 更需要它从元组类型中提供模板 class 的模板参数列表:
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 > >
{};
检查函数然后使用这个助手 class 来实例化另一个 class:
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);
}
我有以下代码,其中有一个模板 class,其中有一个类型,我想在单独的模板函数中使用它。
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);
有没有解决"transfer"模板参数包到模板函数的方法?
无法从嵌套类型推导模板参数。这不是新的或使用可变参数模板更改的。
模板推导是不可能的,但也许你可以用 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);
}
缺点当然是,您必须实例化检查器 class 或使用 MyClass
的正确类型作为模板参数调用函数。
模板参数包可以使用std::tuple传过来。 SomeEnum 类型需要一个包装器 class 通过从它们创建一个元组类型来存储参数包:
template <typename... Types>
struct MyClass
{
struct Value {
enum SomeEnum { value0 = -1 };
enum SomeEnum value;
typedef std::tuple<Types...> TypeTuple;
};
};
比一个助手 class 更需要它从元组类型中提供模板 class 的模板参数列表:
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 > >
{};
检查函数然后使用这个助手 class 来实例化另一个 class:
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);
}