【问题标题】:How is possible to deduce function argument type in C++?如何在 C++ 中推断函数参数类型?
【发布时间】:2014-05-03 03:46:51
【问题描述】:

有函数定义:

void f(int) { }

我要定义:

int a;

但如果函数定义更改为:

void f(double) { }

变量定义必须变成:

double a;

即“a”的类型必须与“f”函数的第一个参数相同。 我需要类似以下的东西:

decltype_of_argument<f, 0> a;

在 C++ 中可以吗?

【问题讨论】:

  • decltype_of_argument 是不可能的,原因与此处解释的原因相同:stackoverflow.com/a/22631749/2694444
  • 所以如果 f 需要一个兽人,你会希望 a 成为一个兽人?
  • @galop1n 仅适用于 f 重载或具有重载 operator()'s 的仿函数
  • “我需要类似下面的东西”为什么?您确实意识到,如果您在这种情况下使用 int a=0,它将被提升为 double,对吧?

标签: c++ function c++11 types


【解决方案1】:

可以通过模板元编程获取类型:

template <class F> struct ArgType;

template <class R, class T> 
struct ArgType<R(*)(T)> {
  typedef T type;
}; 

void f(int) {}

#include <type_traits>
#include <iostream>

int main() {

  // To prove
  std::cout << std::is_same< ArgType<decltype(&f)>::type, int >::value << '\n';

  // To use
  ArgType<decltype(&f)>::type a;
}

根据您想在哪里使用它,您需要将此小模板专门用于其他可调用实体,例如成员函数指针、具有更多参数的函数、仿函数等。Boost 库中有更复杂的方法,请参见例如https://stackoverflow.com/a/15645459/1838266

警告:所有这些实用程序只有在函数/可调用的名称明确映射到单个函数签名时才能工作。如果函数重载或仿函数有多个operator(),则必须通过显式转换为正确的签名来选择正确的函数/运算符,这使得通过模板查找签名的一部分毫无用处。这也以某种方式适用于模板,尽管获取显式专用调用的签名可能仍然有用,例如:

template <unsigned N, class F> struct ArgType; //somewhat more sophisitcated 

template <class T> void f(int, T);

ArgType<0, decltype(&f<double>)> //int    - ArgType has it's use here
ArgType<1, decltype(&f<double>)> //double - here it's useless...

【讨论】:

  • +1 太好了,这就是答案!我试图写这个,但你更快。
  • 注意:如果f 过载,那么ArgType&lt;decltype(static_cast&lt;void(*)(int)&gt;(&amp;f))&gt;::type a; 的用处会越来越小,显然...
  • @MatthieuM。感谢您的提示,问题上的 galop1n 和我的 cmets 都提到了这个问题,我添加它是为了让答案更清楚。
  • 从C++20开始,也可以推断函数参数类型using auto
【解决方案2】:

这取决于你想做什么,应该在哪里使用该变量。如果它在函数中,模板可能是一个不错的选择:

template<typename T>
void foo(T ) {
    T a;
}

或者,如果您在函数之外并且需要真正了解这一点,您可以使用Boost.TypeTraits,即function_traits&lt;void (int)&gt;::arg1_type 将给出int

【讨论】:

  • 使用function_traits&lt;void (int)&gt;::arg1_type得到int?!他为什么不直接写int?!
  • @MM。因为这是简单的形式。实际上,您要么有一个 typedef,要么有一个函数指针,甚至可能指向一个不那么明显的模板。
【解决方案3】:

其中一种方法是使用 typedef 作为函数参数的类型。例如

typedef int TParm;

void f( TParm );

TParm a;

您可以为该类型选择任何名称。例如parm_t 等等。重要的是不会发生名称冲突。

在这种情况下,如果要更改参数的类型,则只需更改 typedef。

或者如果你的编译器支持别名,你也可以写

using TParm = int;

void f( TParm );

TParm a;

您也可以将函数包装在命名空间或类中。:) 例如

struct IFunction
{
   typedef int parm_t;
   static void f( parm_t = parm_t() ) {}
};

//...

IFunction::parm_t a;
IFunction::f( a );

【讨论】:

  • 这可能是最接近 OP 要求的,但我认为最好考虑一下这个的需要......我的意思是可以根据需要转换 double 和 int。
【解决方案4】:

制作模板函数怎么样?

template <typename T>
void f(T t);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 2013-11-10
    • 2020-10-17
    • 2021-04-28
    • 2016-11-01
    • 2022-01-26
    相关资源
    最近更新 更多