gpt4 book ai didi

具有特定签名的 C++ 重载模板

转载 作者:太空狗 更新时间:2023-10-29 21:34:50 27 4
gpt4 key购买 nike

我有以下内容:

struct Args;

template <typename T>
void DoStuff(T&& callback) {
// ... do stuff
MyArgs args = ...
callback(args);
}

太棒了,我可以做到以下几点:

void callback(const Args &);
DoStuff(callback);

和:

DoStuff([](const Args &) { ... });

和:

class CallbackClass {
operator()(const Args &);
};
CallbackClass myCallbackClass;
DoStuff(myCallbackClass);

一切都很好,现在我想在这里做两个改进:

  1. 强制 T 的签名始终为 void(const Args &) 因为在当前状态下我可以执行以下操作:

    void badCallback(Args);
    DoStuff(badCallback);
  2. 允许(除了前面的选项之外)传递具有特定命名成员函数的对象,该成员函数也可以作为回调,例如:

    class NamedCallback {
    void PerformCallback(const Args &);
    };
    NamedCallback myNamedCallback;
    DoStuff(myNamedCallback);

这可能吗?

最佳答案

简单方法

您可以仅使用 std::function 作为参数或原始指针来解决问题。

第一个版本 (std::function) 稍微好一些,因为允许使用对象仿函数

void DoStuff_fn(std::function<void(const Args&)> callback) { callback(Args{}); }

void DoStuff_raw(void (*callback)(const Args&)) { callback(Args{}); }

struct Functor {
void operator()(const Args&) {}
};

// ...
DoStuff_fn(Functor{}); // right call operator() of object
// DoStuff_raw(Functor{}); // error no conversion available

开销(经过优化)非常小,您可以在演示程序集中看到。无论如何,如果您需要关于这些主题的一些高级答案,最好打开一个特定的问题。


关于你的观点:

Enforce that the signature of T is always void(const Args &) because in the current state of things I can do the following:

void badCallback(Args);
DoStuff(badCallback);

Args 可以隐式转换为 const Args&,所以你想要存档的东西是不可能的。无论如何,不​​允许错误的转换(使用我介绍的 DoStuff_fn)。

void bad_callback(Args&) {}

// ...
// DoStuff_fn(bad_callback); // error! cannot cast Args& --> const Args&

高级方法

关于您的问题:

Allow (in addition to the previous options) to pass an object with an specific named member function that would also be allowed to be a callback

这是可能的,但需要一些高级技巧。

在这个问题上我可以建议你的是一种非常简单的方法(利用 C++17 constexpr if)。

如果您需要更强大的东西或C++11 兼容,您应该利用SFINAE(here 一个很好的教程)。

而不是我的方法(使这个问题非常易读和简单):

using Signature = std::function<void(const Args&)>;
template <typename T>
void DoStuff_adv(T&& functor) {
if constexpr (std::is_convertible<T, Signature>::value) {
functor(Args{});
} else {
functor.perform_op(Args{});
}
}

那样的话,T 类型应该是一个带有签名 void(const Args&) 可转换的仿函数,否则,它应该有 perform_op 方法。


Here一个演示。


编辑

如果你想利用 SFINAE,你的方法应该是这样的:

using Signature = std::function<void(const Args&)>;

template <typename T>
typename std::enable_if<std::is_convertible<T, Signature>::value>::type
DoStuff_adv(T&& functor) {
functor(Args{});
}

template <typename T>
typename std::enable_if<has_special_method<T>::value>::type
DoStuff_adv(T&& functor) {
functor.perfom_op(Args{});
}

增强解决方案使用 Boost 库:

#include <boost/tti/has_member_function.hpp>

using Signature = std::function<void(const Args&)>;

template <typename T>
typename std::enable_if<std::is_convertible<T, Signature>::value>::type
DoStuff_adv(T&& functor) {
functor(Args{});
}

BOOST_TTI_HAS_MEMBER_FUNCTION(perform_op)

template <typename T>
typename std::enable_if<
has_member_function_perform_op<void (T::*)(const Args&)>::value>::type
DoStuff_adv(T&& functor) {
functor.perform_op(Args{});
}

关于具有特定签名的 C++ 重载模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45263215/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com