【问题标题】:What is the correct way to check whether a template argument is a "true" callable object?检查模板参数是否是“真正的”可调用对象的正确方法是什么?
【发布时间】:2016-01-08 17:38:27
【问题描述】:

我有以下 C++ 程序:

#include <iostream>
#include <functional>

template<class T> void fun(T t) {
    if (t) std::cout << t();
    else std::cout << "no t";
}

int main() {
    std::function<int ()> f;
    fun(f); //The check will evaluate to false

    fun([](){return "hello";});

    int x = 2;
    fun([x](){return x;}); // Compiler error

    return 0;
}

但它不能编译。问题似乎是捕获某些东西的 lambda 被转换为仿函数对象,而仿函数对象又不能转换为 bool,因此无法检查其真实性。

fun 的正确方法是什么,这样我就可以保留main 的原样?有没有办法在保持简单的同时做到这一点(即不专门化fun)?

编辑:我真的只关心检查t 是否为真,我很高兴假设T 是可调用类型,而无需明确检查。

【问题讨论】:

  • 你会发现更多的搜索网络:“c++ is_callable”
  • 我读了另一个问题,虽然它很相似,但我认为它并不完全相同。这个问题实际上是关于测试某些东西是否是可调用的。就我而言,我知道 T 是可调用类型,但我想知道是否提供了实际的可调用对象。例如,在上面的代码中, f 是可调用的,但是是“空的”。我将编辑问题以使其更清楚。

标签: c++ templates lambda


【解决方案1】:

您将需要进行某种特化或重载,但您至少可以将工作分离到谓词函数中:

template<class T>
typename std::enable_if<
  std::is_constructible<bool, T>::value, bool>::type
okToCall(T&&t) { return static_cast<bool>(t); }
template<class T>
constexpr typename std::enable_if<
  !std::is_constructible<bool, T>::value, bool>::type
okToCall(T&&) { return true; }

template<class T> void fun(T t) {
    if (okToCall(t)) std::cout << t();
    else std::cout << "no t";
}

示例:http://coliru.stacked-crooked.com/a/a08468965ed6d54e

唯一真正的困难是找出调用okToCall 谓词函数的方法——如果T 不能 转换为bool,它的真正作用是返回true,但它的如果它可转换的,则值转换为bool

【讨论】:

  • 我想这回答了 OP 在正文中提出的问题,但不是在标题中。假设是任何可以转换为true 的旧指针都是可调用的,这是错误的。 int b = 42; int* a = &amp;b; fun(a);
  • @AndyG 你是对的,但实际上我只关心检查真实性,并且很高兴假设类型本身是可调用的。我编辑了问题以明确这一点。
  • @ecatmur 谢谢。这确实回答了我的问题,尽管我希望会有一个更小的解决方案,或者像 okToCall 这样的东西会内置在标准库中。
  • @Mitko 是的,抱歉 - 目前这种语言并不是特别擅长这种事情。某种静态 if 设施(例如 n4461 或 baptiste-wicht.com/posts/2015/07/…)将允许对其进行编码而不会重载。
猜你喜欢
  • 2018-08-16
  • 1970-01-01
  • 2013-01-13
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2019-09-16
相关资源
最近更新 更多