C++ - 为什么 std::function<some_type_t, void> 无效?

C++ - Why is std::function<some_type_t, void> invalid?

在 C++ 中,如果我尝试这样做:

std::function<void(bool,void)>

然后编译器会抛出错误。为什么是这样?它在许多情况下很有用。一个例子:

//g++ -std=c++17 prblm.cpp
#include <cstdio>
#include <functional>

template<class type_t>
class some_callback
{
    public:
        using callback_t = std::function<void(bool,type_t)>;
        some_callback(callback_t _myfunc)
        {
            this->myfunc = _myfunc;
        }
        callback_t myfunc;
};

using callback_with_just_bool = some_callback<void>;
using callback_with_an_int_too = some_callback<int>;

int main()
{
    auto my_callback_with_int = callback_with_an_int_too([](bool x, int y)
    {
    }); //OK

    auto my_callback_just_bool = callback_with_just_bool([](bool x)
    {
    }); //Error

    auto my_callback_just_bool = callback_with_just_bool([](bool x,void z)
    {
    }); //Error
    return 0;
}

如果用户希望在他们的回调中有选择地包含额外的数据,但不是必须的,这允许一个非常干净的语法。但是,编译器将拒绝尝试初始化 callback_with_just_bool

对象的代码

为什么会这样,是否有解决方法?谢谢。

编辑:在现实世界的代码中,我尝试这样做的具体原因是在事件系统中。向事件系统提供了有关希望 有条件地 接收事件 (e.x. "if you're close enough to the source, you'll receive a sound event") 的单个对象的数据,以及向回调提供的数据 关于事件(e.x。"a 10khz noise at X200 Y200")。大多数时候,检查需求所需的数据将存在于提供给事件回调 about 的数据中,但如果不是,我想提供一个可选的附加数据结构案件。因此,如果用户不需要这个额外的数据结构,他们会指定 "void"。

问题不在于您显示的代码,这是因为在 C/C++ 中,您无法将函数 f 定义为

void f(bool b, void v) {}

原因是,正如@Peter Ruderman 所说,void 不是有效的参数类型。

您可以创建专业化:

template<class type_t>
class some_callback
{
    std::function<void(bool,type_t)> myfunc;
};

template<>
class some_callback<void>
{
    std::function<void(bool)> myfunc;
};

可变参数模板是一种方法:

template <class... T>
struct some_callback
{
  std::function<void(bool, T...)> myfunc;
};

using callback_with_just_bool = some_callback<>;
using callback_with_an_int_too = some_callback<int>;

使用别名模板更简洁:

template <class... T> using callback_type = std::function<void(bool, T...)>;

int main()
{
  callback_type<int> my_callback_with_int = [](bool x, int y)
  {
  }; //OK

  callback_type<> my_callback_just_bool = [](bool x)
  {
  }; //OK now too...
}

“这是为什么?”

因为 void 在参数列表中唯一允许的用法是表明该函数不接受任何参数。

来自 [function]:

void

Indicates that the function takes no parameters, it is the exact synonym for an empty parameter list: int f(void); and int f(); declare the same function. Note that the type void (possibly cv-qualified) cannot be used in a parameter list otherwise: int f(void, int); and int f(const void); are errors (although derived types, such as void* can be used)

“有解决办法吗?”

我建议专攻 void:

template<class type_t>
class some_callback
{
    std::function<void(bool,type_t)> myfunc;
};

template<>
class some_callback<void>
{
    std::function<void(bool)> myfunc;
};

其他答案已经解释了原因。这回答了 "is there a clean way around it?"

我通常为回调做的是使用 lambdas。

std::function<void(void)> myfunc;

bool b = false;
int i = 42;

myfunc = [&]() { if (b) ++i; };

有人建议将 "regular void" 添加到语言中。

其中,void 成为所有其他类型隐式转换为的单态类型。

你可以用

来模拟这个
struct monostate_t {
  template<class T>
  monostate_t(T&&) {}
};

然后

using callback_with_just_bool = some_callback<monostate_t>;
auto my_callback_just_bool = callback_with_just_bool([](bool x, auto&&...)
{
});

大致按照你喜欢的方式工作。