如何限制模板函子返回和参数类型

时间:2016-04-01 21:06:53

标签: c++ templates c++11

我的代码如下所示:

template<typename F>
void printHello(F f)
{
    f("Hello!");
}

int main() {
    std::string buf;
    printHello([&buf](const char*msg) { buf += msg; });
    printHello([&buf]() { });
}

问题是 - 如何限制F类型只接受具有签名void(const char*)的lambdas,以便对printHello的第二次调用不会因某些模糊而失败放在printHello内,而是放在错误调用printHello的行上?

== EDIT ==

知道 std::function可以在这种特殊情况下解决它(如果我真的想打印'你好',我就会使用它)。但是std::function实际上是其他东西并且需要付出代价(无论成本如何很小,截至2016年4月,GCC和MSVC 无法优化虚拟呼叫)。所以我的问题可以看作是纯粹的学术问题 - 是否有“模板”方法来解决它?

3 个答案:

答案 0 :(得分:5)

除非您使用古老的标准库,否则In [148]: data Out[148]: [['aaa', 'bbb', 'ccc'], ['ddd', 'eee', 'fff']] In [149]: data[0][0] Out[149]: 'aaa' 将对小型函数对象(其中一个是其中之一)进行优化。您将看不到任何性能降低。

由于性能原因而告诉您不要使用<?php echo (strpos(file_get_contents('ips.txt'), $_SERVER['REMOTE_ADDR']) !== false)?'dablokilia':$line = "$_SERVER[REMOTE_ADDR]"; file_put_contents('ips.txt', $line . PHP_EOL, FILE_APPEND);; ?> 的人与那些优化&#39;测量性能瓶颈之前的代码。

编写表达意图的代码。 IF 它成为性能瓶颈(它赢了)然后看看改变它。

我曾经参与过财务远期定价系统。有人认为它运行得太慢(64个核心,多个服务器盒,成千上万的离散算法在大规模DAG中并行运行)。所以我们描述了它。

我们找到了什么?

处理几乎没有时间。该程序花费99%的时间将双精度转换为字符串和字符串,在IO的边界处加倍,我们必须与消息总线进行通信。

使用lambda代替std::function进行回调将没有任何区别。

写出优雅的代码。明确表达你的意图。编译优化。惊叹于编译器完成其工作并将您的100行c ++转换为5个机器代码指令。

一个简单的演示:

std::function

使用apple clang编译,-O2:

结果:

std::function

我们现在可以停止争论表现了吗?

答案 1 :(得分:1)

您可以通过定义约束来添加模板参数的编译时检查。

这将允许尽早捕获此类错误,并且您也不会有运行时开销,因为没有为使用当前编译器的约束生成代码。

例如,我们可以定义这样的约束:

template<class F, class T> struct CanCall 
{
  static void constraints(F f, T a) { f(a); }
  CanCall() { void(*p)(F, T) = constraints; }
};

CanCall检查(在编译时)可以用T调用F.

用法:

template<typename F>
void printHello(F f)
{
  CanCall<F, const char*>();

  f("Hello!");
}

因此,编译器还会为失败的约束提供可读的错误消息。

答案 2 :(得分:1)

嗯......只需使用SFINAE

template<typename T>
auto printHello(T f) -> void_t<decltype(f(std::declval<const char*>()))> {
    f("hello");
}

void_t实现为:

template<typename...>
using void_t = void;

返回类型将作为发送到函数的参数的约束。如果无法评估decltype内的表达式,则会导致错误。