gpt4 book ai didi

c++ - 如何为模板回调参数强制执行特定签名

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:12:07 30 4
gpt4 key购买 nike

我希望能够在使用模板化回调参数时强制执行特定的回调签名。目标有三方面:

  1. 在用户调用点得到一个编译器错误,而不是深入到接受回调的方法。
  2. 遵守最小意外原则,防止用户提供返回值的回调,而使用回调的实现不会检查其值等(精确签名匹配)
  3. 尽可能使用地道的 C++ 和最佳实践。高效。

来自 C#,我首先尝试像这样模仿 Action 和 Func 类:

template<typename ...TArgs> using Action = std::function<void(TArgs...)>;
template<typename TRet, typename ...TArgs> using Func = std::function<TRet(TArgs...)>;

这工作正常,除了它使用 std::function ,我听说要避免这个“简单”任务(失败 #3)。另外,不幸的是,它也没有满足我上面的#2 要求:

void DoActionStuff(Action<int, float> callback)
{
callback(1, 2.0);
}

void DoFuncStuff(Func<float, int, float> callback)
{
float result = callback(1, 2.0);
if (result > 100.0) { throw runtime_error("derp"); };
}

DoActionStuff([](int x, float y) { cout << x << " " << y << endl; }); // OK
DoActionStuff([](int x, float y) { cout << x << " " << y << endl; return x * y; }); // No error :( Why not?

DoFuncStuff([](int x, float y) { cout << x << " " << y << endl; }); // OK - We get a compiler error right here at the call-site for this one...
DoFuncStuff([](int x, float y) { cout << x << " " << y << endl; return x * y; }); // OK

我如何通过执行以下操作来满足所有 3 个要求?有没有什么好的 trait 魔法可以用来为该方法提供更好的签名,以准确传达所需的回调类型?

template<typename TCallback>
void DoStuff(TCallback callback) { ... } // Unnecessarily burdens the client of this api (they have no idea the signature to use here)

最佳答案

老实说,我会坚持你的第一直觉,而不是类型别名:

void DoAction(std::function<void(int, float)> );
void DoFuncStuff(std::function<float(int, float)> );

在调用站点上可以清楚地看到这些函数的期望,它们已经为您进行了有效性检查。他们不会完全检查签名 - 但这真的是您想要的吗? DoAction() 的可调用对象的任何返回值都将被忽略,参数类型将允许隐式转换。但这在 C++ 中无处不在。此外,这允许更复杂的构造,例如传递通用 lambda:

DoFuncStuff([](auto i, auto f){ return f; }); // really want to disallow this?

你当然可以这样写:

// function pointer case
template <class R, class... Args> std::true_type check_member(R (*)(Args...) );

// function object case
template <class F, class R, class... Args> std::true_type check_member(R (F::*)(Args...) );
template <class F, class R, class... Args> std::true_type check_member(R (F::*)(Args...) const );
template <class R, class... Args, class F> auto check_member(F& ) -> decltype(check_member<F, R, Args...>(&F::operator()));

// failure case
template <class... > std::false_type check_member(...);

template <class F>
void DoAction(F f) {
static_assert(
decltype(check_member<void, int, float>(f))::value,
"invalid signature"
);

// body
}

但这远没有您最初的想法那么清晰。您需要 check_member 来正确处理重载和模板化的 operator()


通常对某些异常(exception)情况取模。

关于c++ - 如何为模板回调参数强制执行特定签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39632011/

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