Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用两个以上参数推导std::函数_C++_C++11_Templates_Template Argument Deduction - Fatal编程技术网

C++ 使用两个以上参数推导std::函数

C++ 使用两个以上参数推导std::函数,c++,c++11,templates,template-argument-deduction,C++,C++11,Templates,Template Argument Deduction,我想知道为什么它只知道两个参数函数。我已经编写了一些工作正常的代码,但是有一些限制。欢迎任何反馈。特别是,我怀疑我正在重新发明轮子 我的代码已打开,我将参考它 例如,我可以用以下内容描述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的指针)

我想知道为什么它只知道两个参数函数。我已经编写了一些工作正常的代码,但是有一些限制。欢迎任何反馈。特别是,我怀疑我正在重新发明轮子

我的代码已打开,我将参考它

例如,我可以用以下内容描述
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
不适用于具有两个以上参数的函数(请参阅我代码的最后两行),但此代码适用(示例代码演示了三个参数函数)。也许我的设计应该在标准库中使用!我将
typedef元组args\u定义为\u元组
存储所有参数,而不仅仅是前两个参数类型

主要技巧是此函数中的演绎:

template<class T, class... Args>
auto function_type_deducer(T(Args...)) -> Function__<T, Args...> {
        return Function__<T, Args...> {};
}
模板
自动函数类型推断器(T(参数…)->函数{
返回函数{};
}
限制:

  • 它不适用于lambdas。这不会编译
    函数类型推导器([](){})
  • 它没有注意到
    x
    y
    之间有一点区别,因为
    y
    接受
    字符串&
    ,其中
    x
    接受
    字符串
    。(std::函数也没有注意到这一点)
有没有关于如何解决这两个问题的想法?我重新发明了轮子吗

这不会编译
函数类型推导器([](){})

如果
function\u type\u explorer
不是一个模板,它就会起作用。:)非捕获lambda(空
[]
)可隐式转换为函数指针。遗憾的是,一些模板参数推导没有考虑隐式转换。有关更多信息,请参阅(请注意,我的答案并非如评论所示完全正确)


它没有注意到x和y之间有一个小的区别,因为y接受一个字符串&,其中x接受一个字符串

这不是函数的问题,而是
typeid
的问题,正如这个简单的测试代码所示:

template<class T>
void x(void(T)){
    T v;
    (void)v;
}

void f1(int){}
void f2(int&){}

int main(){
    x(f1);
    x(f2);
}
。输出:

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'

lambda函数的答案链接提供了关键提示:您需要为函数调用操作符获取指向成员函数的指针。也就是说,如果
T
是函数对象,则需要查看
&T::operator()
。使用广义SFINAE,您可以确定此函数调用运算符是否存在。以一种可能有点迂回的方式将这些内容组合在一起,可以得到以下结果(使用最新版本的gcc和clang编译,除了clang不支持的lambda函数):

#包括
#包括
#包括
#包括
#包括
#包括
// -----------------------------------------------------------------------------
结构{
void f(int,std::string&,void(*)(int)){
void g(int,std::string&,void(*)(int))常量{
};
// -----------------------------------------------------------------------------
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符;
模板结构描述符{
静态std::string type(){return“?”;}
};
模板结构描述符{
静态std::string type(){return“S”;}
};
模板结构描述符{
静态std::string type(){返回“void”;}
};
模板结构描述符{
静态std::string type(){return“int”;}
};
模板结构描述符{
静态std::string type(){返回“std::string”;}
};
模板结构描述符{
静态std::string type(){return descripber::type()+std::string(“&”);}
};
模板结构描述符{
静态std::string type(){返回描述符::type()+std::string(&&&)}
};
模板结构描述符{
静态std::string type(){return descripber::type()+std::string(“&”);}
};
模板结构描述符{
静态std::string type(){返回描述符::type()+std::string(“const”);}
};
模板结构描述符{
静态std::string type(){return descripber::type()+std::string(“volatile”);}
};
模板结构描述符{
静态std::string type(){return descripber::type()+std::string(“const volatile”);}
};
模板结构描述符
{
静态std::字符串类型(){
std::ostringstream out;
out::type description(std::string const&what,T)
{

std::cout看起来与我的lambda问题有关。从这个答案来看,可能对所有这些都有答案。也许这毕竟是一个重复!
std::函数
只包含
参数类型
第一个参数类型
,以及
第二个参数类型
typedef,以便向后兼容C++98/03代码关于TR1之前的函数适配器,我有点担心。本质上,它们是传统的,在C++11中,你应该尽力假装它们不存在。@ildjarn:C++11获取参数n类型的方法是什么?听起来这是一个有效的答案。@Drew:Unpacking
Args…
std::tuple
typedef中,然后访问tuple元素我猜是s by index,但我对变量模板的了解还不够,无法给出一个真正的答案。@Xeo:clang进展得很好,我想。我不知道他们的计划是什么。我当然想使用lambda函数,但这似乎是更好的,但还不值得依赖。@DietmarKühl,答案也不错,但我很瘦k我会接受Xeo的,因为他的代码有点短。[就像“code golf是一个用最少字节的源代码来解决特定问题的比赛。”:-)]+1.谢谢。我刚刚通过找到了另一个简单得可笑的模板。只要看看ideone就知道了。就好像专业化已经实现了
#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'
#include <iostream>
#include <sstream>
#include <string>
#include <typeinfo>
#include <functional>
#include <utility>

// -----------------------------------------------------------------------------

struct S {
    void f(int, std::string&, void (*)(int)) {}
    void g(int, std::string&, void (*)(int)) const {}
};

// -----------------------------------------------------------------------------

template <typename T> struct describer;
template <> struct describer<S>;
template <> struct describer<int>;
template <> struct describer<void>;
template <> struct describer<std::string>;
template <typename T> struct describer<T&>;
template <typename T> struct describer<T*>;
template <typename T> struct describer<T const>;
template <typename T> struct describer<T volatile>;
template <typename T> struct describer<T const volatile>;
template <typename T, int Size> struct describer<T(&)[Size]>;

template <typename T> struct describer {
    static std::string type() { return "???"; }
};
template <> struct describer<S> {
    static std::string type() { return "S"; }
};
template <> struct describer<void> {
    static std::string type() { return "void"; }
};
template <> struct describer<int> {
    static std::string type() { return "int"; }
};
template <> struct describer<std::string> {
    static std::string type() { return "std::string"; }
};
template <typename T> struct describer<T&> {
    static std::string type() { return describer<T>::type() + std::string("&"); }
};
template <typename T> struct describer<T&&> {
    static std::string type() { return describer<T>::type() + std::string("&&"); }
};
template <typename T> struct describer<T*> {
    static std::string type() { return describer<T>::type() + std::string("&"); }
};
template <typename T> struct describer<T const> {
    static std::string type() { return describer<T>::type() + std::string(" const"); }
};
template <typename T> struct describer<T volatile> {
    static std::string type() { return describer<T>::type() + std::string(" volatile"); }
};
template <typename T> struct describer<T const volatile> {
    static std::string type() { return describer<T>::type() + std::string(" const volatile"); }
};
template <typename T, int Size> struct describer<T(&)[Size]>
{
    static std::string type() {
        std::ostringstream out;
        out << "(array of " << Size << " " << describer<T>::type() << " objects)&";
        return out.str();
    }
};

template <typename... T> struct description_list;
template <> struct description_list<> { static std::string type() { return std::string(); } }; 
template <typename T> struct description_list<T> { static std::string type() { return describer<T>::type(); } };
template <typename T, typename... S> struct description_list<T, S...> {
    static std::string type() { return describer<T>::type() + ", " + description_list<S...>::type(); }
};

template <typename R, typename... A>
struct describer<R(*)(A...)>
{
    static std::string type() {
        return "pointer function returning " + describer<R>::type() + " and taking arguments"
            + "(" + description_list<A...>::type() + ")";
    }
};

template <typename R, typename S, typename... A>
struct describer<R(S::*)(A...)>
{
    static std::string type() {
        return "pointer to member function of " + describer<S>::type() + " returning " + describer<R>::type() + " "
            "and taking arguments" + "(" + description_list<A...>::type() + ")";
    }
};

template <typename R, typename S, typename... A>
struct describer<R(S::*)(A...) const>
{
    static std::string type() {
        return "pointer to const member function of " + describer<S>::type() + " returning " + describer<R>::type() + " "
            "and taking arguments" + "(" + description_list<A...>::type() + ")";
    }
};

template <typename T> char (&call_op(decltype(&T::operator())*))[1];
template <typename T> char (&call_op(...))[2];

template <typename T> struct has_function_call_operator { enum { value = sizeof(call_op<T>(0)) == 1 }; };

template <typename T>
typename std::enable_if<!has_function_call_operator<T>::value>::type describe(std::string const& what, T)
{
    std::cout << "describe(" << what << ")=" << describer<T>::type() << "\n";
}

template <typename T>
typename std::enable_if<has_function_call_operator<T>::value>::type describe(std::string const& what, T)
{
    std::cout << "describe(" << what << ")=function object: " << describer<decltype(&T::operator())>::type() << "\n";
}


int f(std::string, std::string const&, std::string&&) { return 0; }
int g(std::string&, std::string const&) { return 0; }

int main()
{
    describe("int", 1);
    describe("f", &f);
    describe("g", &g);
    describe("S::f", &S::f);
    describe("S::g", &S::g);
    describe("mini-lambda", []{}); // doesn't work with clang, yet.
    describe("std::function<int(int(&)[1], int(&)[2], int(&)[4], int(&)[4])>",
             std::function<int(int(&)[1], int(&)[2], int(&)[4], int(&)[4])>());
}