c++ 函数类型可以是类模板参数吗?

zpqajqem  于 2023-05-02  发布在  其他
关注(0)|答案(4)|浏览(114)

下面的代码被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;
}

为什么?

gjmwrych

gjmwrych1#

gcc对这个错误更友好一点:

error: field 'A<int(int)>::bar' invalidly declared function type

最简单的解决方案是将bar声明为函数指针:

FunctionPtr *bar;

在这种情况下,decltype(Hello)计算为int(int)而不是int(*)(int)

byqmnocz

byqmnocz2#

变量不能有函数类型。声明barFunctionPtr,即decltype(Hello),计算结果为int (int),而不是函数指针类型。
这是令人困惑的,因为从C继承了一些不一致的地方。当您将A的构造函数定义为接受一个FunctionPtr时,您可能会想到您会得到相同的错误。然而,声明为具有数组或函数类型的函数参数自动(不幸的是,不方便)转换为指针类型。因此,即使foo被声明为具有函数类型,但它实际上具有函数指针类型并且工作正常。
但是这个规则只适用于函数参数,而不适用于其他变量,所以bar实际上确实有一个函数类型,这是不法律的的。

toe95027

toe950273#

加上其他答案,您可以利用以下事实:

下面的代码:

#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 << "Function\n"; }

struct Hello2 { void operator()() { std::cout << "Struct\n"; } };

void Hello3() { std::cout << "Function pointer\n"; }

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 << "Lambda\n"; };
  A<decltype(Hello4)> d(Hello4);
}

(here我利用C++14的特性稍微改变了解决方案)。
事实上,std::function是一个(并不总是更好的)替代方案。

qxsslcnc

qxsslcnc4#

今天刚刚遇到这个-如果你用decltype((Hello))运行它应该没问题,而不必更改代码。详情见Scott Meyers

相关问题