c – 使用两个以上的arg推导std :: function
作者:互联网
我想知道为什么std::function
只知道两个参数的功能.我写了一些运行良好的代码,但是有很多限制.任何反馈欢迎.特别是,我怀疑我正在重新发明轮子.
我的代码是ideone,我会参考它.
例如,我可以用以下内容描述main的类型:
function_type_deducer(main).describe_me();
// Output: I return i and I take 2 arguments. They are of type: i PPc
(其中’i’表示’int’,’PPc’表示指向指针指向char的指针)
标准std :: function不适用于具有两个以上args的函数(请参阅我的代码的最后两行),但此代码可以使用(示例代码演示了三个arg函数).也许我的设计应该在标准库中使用!我定义了typedef元组< Args ...> args_as_tuple;存储所有args,而不仅仅是前两个参数类型.
主要技巧是这个函数的推论:
template<class T, class... Args>
auto function_type_deducer(T(Args...)) -> Function__<T, Args...> {
return Function__<T, Args...> {};
}
限制:
>它不适用于lambdas.这不会编译function_type_deducer([](){}).describe_me();
>它没有注意到x和y之间存在小的差异,因为y取一个字符串&,其中x取一个字符串. (std :: function也没有注意到这一点)
关于如何修复其中任何一个的任何想法?我重新改造了车轮吗?
解决方法:
This won’t compile
function_type_deducer([](){}).describe_me();
如果function_type_deducer不是模板,它将起作用. :)非捕获lambdas(empty [])可以隐式转换为函数指针.遗憾的是,对于某些模板参数推导,不考虑隐式转换.有关详细信息,请参阅this question(请注意,我的答案并不完全正确,如评论所示).
It doesn’t notice that there is a small difference between x and y, as y takes a string&, where x takes a string.
这不是函数的问题,这是typeid的一个问题,因为这个简单的测试代码显示:
template<class T>
void x(void(T)){
T v;
(void)v;
}
void f1(int){}
void f2(int&){}
int main(){
x(f1);
x(f2);
}
error: ‘v’ declared as reference but not initialized
一个简单的修复可能是使用标签分派:
#include <type_traits> // is_reference
#include <iostream>
#include <typeinfo>
template<class T>
void print_name(std::true_type){
std::cout << "reference to " << typeid(T).name();
}
template<class T>
void print_name(std::false_type){
std::cout << typeid(T).name();
}
template<class T>
void print_name(){
print_name(typename std::is_reference<T>::type());
}
并调用print_name< NextArg>()而不是typeid(NextArg).name().
Have I reinvented the wheel?
是的,有点和不,你没有. Boost.Function为所有参数(argN_type样式)提供typedef,以及其数量的静态常量arity.但是,您无法轻松访问这些typedef.你需要一种迂回的方式来不意外地访问不存在的方法.元组的想法效果最好,但它可以用更好的方式编写.这是我曾写过的东西的修改版本:
#include <tuple>
#include <type_traits>
#include <iostream>
#include <typeinfo>
namespace detail{
template<class T>
std::ostream& print_name(std::ostream& os);
template<class T>
std::ostream& print_pointer(std::ostream& os, std::true_type){
typedef typename std::remove_pointer<T>:: type np_type;
os << "pointer to ";
return print_name<np_type>(os);
}
template<class T>
std::ostream& print_pointer(std::ostream& os, std::false_type){
return os << typeid(T).name();
}
template<class T>
std::ostream& print_name(std::ostream& os, std::true_type){
return os << "reference to " << typeid(T).name();
}
template<class T>
std::ostream& print_name(std::ostream& os, std::false_type){
return print_pointer<T>(os, typename std::is_pointer<T>::type());
}
template<class T>
std::ostream& print_name(std::ostream& os){
return print_name<T>(os, typename std::is_reference<T>::type());
}
// to workaround partial function specialization
template<unsigned> struct int2type{};
template<class Tuple, unsigned I>
std::ostream& print_types(std::ostream& os, int2type<I>){
typedef typename std::tuple_element<I,Tuple>::type type;
print_types<Tuple>(os, int2type<I-1>()); // left-folding
os << ", ";
return print_name<type>(os);
}
template<class Tuple>
std::ostream& print_types(std::ostream& os, int2type<0>){
typedef typename std::tuple_element<0,Tuple>::type type;
return print_name<type>(os);
}
} // detail::
template<class R, class... Args>
struct function_info{
typedef R result_type;
typedef std::tuple<Args...> argument_tuple;
static unsigned const arity = sizeof...(Args);
void describe_me(std::ostream& os = std::cout) const{
using namespace detail;
os << "I return '"; print_name<result_type>(os);
os << "' and I take '" << arity << "' arguments. They are: \n\t'";
print_types<argument_tuple>(os, int2type<arity-1>()) << "'\n";
}
};
main: I return 'i' and I take '2' arguments. They are:
'i, pointer to pointer to c'
x: I return 'Ss' and I take '3' arguments. They are:
'i, Ss, c'
y: I return 'Ss' and I take '3' arguments. They are:
'i, reference to Ss, c'
标签:template-deduction,c,c11,templates 来源: https://codeday.me/bug/20190826/1731495.html