函数类型可以是类模板参数吗?
Can a function type be a class template parameter?
>下面的代码被VC++ 2012拒绝,并显示"错误C2207:'A::bar':类模板的成员无法获取函数类型"。
int Hello(int n)
{
return n;
}
template<class FunctionPtr>
struct A
{
A(FunctionPtr foo)
: bar(foo)
{}
FunctionPtr bar;
};
int main()
{
A<decltype(Hello)> a(Hello);
return 0;
}
为什么?
gcc 对此错误更友好:
error: field 'A<int(int)>::bar' invalidly declared function type
最简单的解决方案是将bar
声明为函数指针:
FunctionPtr *bar;
在这种情况下,decltype(Hello)
计算结果为int(int)
不int(*)(int)
。
变量不能有函数类型。你声明bar
是FunctionPtr
这是decltype(Hello)
计算结果为int (int)
的,而不是函数指针类型。
由于从 C 继承的一些不一致,这令人困惑。当您将A
的构造函数定义为采用FunctionPtr
时,您可能会认为您会收到相同的错误。但是,声明为具有数组或函数类型的函数参数会自动(不幸的是,不方便)转换为指针类型。因此,即使foo
被声明为具有函数类型,它实际上也具有函数指针类型并且工作正常。
但是这个规则只适用于函数参数,而不适用于其他变量,所以bar
实际上确实有一个函数类型,这是不合法的。
加上其他答案,您可以利用以下事实:
decltype(Hello)
计算结果为int (int)
(而不是函数指针类型);- 函数可以隐式转换为指向自身的指针;这种转换几乎无处不在(例如,按值(?)传递函数而不是函数指针?)。
以下代码:
#include <type_traits>
template<class F>
struct A
{
A(F foo) : bar(foo) {}
typename std::conditional<std::is_function<F>::value,
typename std::add_pointer<F>::type,
F>::type bar;
};
是一个通用解决方案,允许对函数、函数指针、函子和 lambda 使用相同的语法:
#include <type_traits>
#include <iostream>
void Hello() { std::cout << "Functionn"; }
struct Hello2 { void operator()() { std::cout << "Structn"; } };
void Hello3() { std::cout << "Function pointern"; }
template<class F>
struct A
{
A(F foo) : bar(foo) { bar(); }
std::conditional_t<std::is_function<F>::value, std::add_pointer_t<F>, F> bar;
};
int main()
{
A<decltype(Hello)> a(Hello);
Hello2 h2;
A<decltype(h2)> b(h2);
A<decltype(&Hello3)> c(&Hello3);
auto Hello4 = []() { std::cout << "Lambdan"; };
A<decltype(Hello4)> d(Hello4);
}
(在这里,我利用C++14功能稍微更改了解决方案)。
事实上,std::function
是一个(并不总是更好的)选择。
今天刚遇到这个问题 - 如果你用decltype((Hello))
运行它,应该没问题,而无需更改代码。详见斯科特·迈耶斯
相关文章:
- 扩展C++生成的代码的模板参数类型名称
- 如何在 c++ 中定义接受不同参数类型的函数向量?
- 在 C++ 中运行时调用模板时,是否可以切换模板的参数类型?
- 将函数参数类型声明为 auto
- 将函数的参数 - 签名从使用 'std::function<T>' 转换为模板参数类型
- 在 C++17 中调用具有不同参数类型的构造函数
- 具有先前参数类型匹配的参数包
- 我想知道为什么"std::unique_ptr<int> foo(新 int)"是合法的,因为"std::<int>unique_ptr"要求输入参数类型应该是"int"?
- 将可变参数类型列表的扩展打包为复杂类型的初始值设定项列表 - 合法吗?
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- 如何从第一个参数推断第二个参数类型?
- C++模板函数中,指定回调函子/lambda 的参数类型,同时仍允许内联?
- 如何用不同的参数类型和数字回调函数
- C++stoi:这两个重载都无法转换所有参数类型
- 为什么std::{container}::template不能推导其参数类型
- 为模板参数类型中的新对象分配内存
- 为指向成员模板参数的指针推导额外模板参数类型的紧凑方式
- 使用std::conditional中的模板来确定函数参数类型
- C++中的短参数类型