我无法让这个虚拟模板化仿函数运算符返回正确的类型

时间:2017-09-26 05:48:12

标签: c++ templates generics virtual

我已经在这里待了很长时间。基本上,类接受一个类型,它可能是一个函数,还有一些参数:

template <typename T, typename ... Args>
struct HandlerBase
{
    HandlerBase(T type, Args ... args) {}
    HandlerBase() {}

     auto operator()(Args ... args) 
        { return std::declval<T>()(args...); }  ;
};// This compiles

但现在我想让我的operator()虚拟,我得到错误:

  

&#34;虚拟成员函数不应具有包含的返回类型   自动&#34;

所以我需要手动设置返回类型,并且在我所有搜索之后我可以尝试的最好:

virtual decltype(std::declval<T>()(std::declval<Args>()...)) 
operator()(Args ... args)
{ return std::declval<T>()(args...); }  ;

或作为追踪回报

virtual auto operator()(Args ... args)
-> decltype(std::declval<T>()(std::declval<Args>()...))
{ return std::declval<T>()(args...); }  ;

这些尝试是基于我之前对此主题的一些帮助。我真的觉得通过这样的陈述几乎不可能解析。

如果有人想尝试,这就是整个事情的样子:

#include <iostream>

template <typename T, typename ... Args>
struct HandlerBase
{
    HandlerBase(T type, Args ... args) {}
    HandlerBase() {}

     virtual decltype(std::declval<T>()(std::declval<Args>()...)) operator()(Args ... args)
        { return std::declval<T>()(args...); }  ;
};

int main()
{
    auto lambda = []() { return 0; };
    HandlerBase<decltype(lambda)> object;   
}

在正常返回语法和尾随返回语法的Visual Studio上我得到错误我得到一个基本上不可读的链接器错误,但是它提到了返回类型为int的东西,所以我认为我在括号内的实际定义可能是错的。

2 个答案:

答案 0 :(得分:2)

std::declval只能用于未评估的环境中。正如其documentation on cppreference所示:

  

请注意,因为declval不存在定义,所以它只能是   用于未评估的背景;评估表达式是错误的   包含此功能。在形式上,如果,该计划是不正确的   这个功能很奇怪。

当您编写std::declval<T>()(args...)时,它会尝试使用引用declval返回来调用函数调用运算符。这是一个有趣的用途,链接器必须查找它。它无法找到它,因此也就是错误。

只有在添加虚拟说明符时才触发它,因为虚函数是隐式使用的(主要是因为它们必须是为了添加动态调度支持)。

如果没有虚拟说明符,operator()的函数体将永远不会被实例化,直到尝试调用它(在作为模板类的帐户HandlerBase<>上)。但如果您尝试在原始版本中调用operator(),那么您将获得完全相同的链接器错误#34;工作&#34;版本

答案 1 :(得分:1)

您可以使用标准result_of

实现您的需求
typename std::result_of<T(Args...)>::type

整个事情看起来像这样:

template <typename T, typename ... Args>
struct HandlerBase
{
    HandlerBase(T type, Args ... args) {}
    HandlerBase() {}

    virtual auto operator()(Args ... args)
    -> typename std::result_of<T(Args...)>::type
    { return T()(std::forward<Args>(args)...); };
};

<强>被修改

正如所指出的那样,std::result_of在c ++ 17中被std::invoke_result替换。

以下是使用std::invokestd::invoke_result的替代实现:

#include <utility>
#include <iostream>
#include <functional>

template <typename T, typename ... Args>
struct HandlerBase
{
    HandlerBase() {}

    virtual auto operator()(T type, Args ... args)
    -> typename std::invoke_result_t<T, Args...>
    { return std::invoke(type, args...); };
};

int main()
{
    auto lambda = []() { return 0; };
    HandlerBase<decltype(lambda)> object;
}