如何存储指向函数模板的指针,该函数模板将Callable对象作为其参数之一

时间:2017-06-24 18:52:14

标签: c++ c++14

请考虑以下示例:

template <typename T>
void f (T t) {
    std::cout << t << std::endl;
}


template <typename T>
struct F { 
    static constexpr void (*m) (T) = &f; 
};

和用法:

F<int>::m (10);

到目前为止,这么好。当我想存储指向函数模板的指针时出现问题,该函数模板采用例如lambda表达式。考虑一下这个:

template <typename T, typename C>
void g (T t, C c) {
    std::cout << c (t) << std::endl;
}

template <typename T, typename C>
struct G { 
    static constexpr void (*m) (T, C) = &g; 
}; 

和用法:

auto l = [] (auto v) { return v; };
G<int, decltype (l)>::m (20, l); 

在GCC 5.3.1上编译:

g++-5 -std=c++14 -Wall -Wextra -Wpedantic -Werror=return-type main.cpp -o main

我得到了:

‘constexpr void (* const G<int, main(int, char**)::<lambda(auto:1)> >::m)(int, main(int, char**)::<lambda(auto:1)>)’, declared using local type ‘main(int, char**)::<lambda(auto:1)>’, is used but never defined [-fpermissive]

为什么会这样?

有什么方法可以让我的代码工作吗?

我不感兴趣的一种可能的解决方案:

struct O { 
    template <typename T>
    T operator() (T v) {
        return v;
    }   
};

用法:

G<int, O>::m (20, O {});

1 个答案:

答案 0 :(得分:4)

错误,如果你删除一些东西,说:

  

[...] m [...]被使用但从未定义[-fpermissive]

所以只需按照编译器的命令进行定义:

template <class T, class C>
constexpr void (*G<T,C>::m)(T,C);

现在它有效。这是因为在C ++ 14中,您需要从[class.static.data]添加静态constexpr数据成员的定义:

  

如果程序中使用了odr-used([basic.def.odr]),并且命名空间范围定义不包含初始值设定项,那么[静态数据]成员仍应在命名空间作用域中定义。

p0386导致constexpr静态数据成员在C ++ 17中不再需要这样做。文字now reads

  

如果使用constexpr说明符声明[static data]成员,则可能在名称空间作用域中重新声明而没有初始化程序(不推荐使用此用法;请参阅[depr.static_constexpr] )。