clang++:候选函数[带有callable_t = void(int,double),args_t =< int,double>]不可行:期望第三个参数的rvalue
我有一个测试框架,我需要捕获对通用函数(测试套件)的调用并稍后执行它。
为此,我使用带有参数包的类模板,并将参数存储在元组中。
在 GCC 10 和 GCC 11 中一切都构建并运行良好,但在 clang 中失败。
代码如下所示:
template <typename Callable_T, typename... Args_T>
class test_suite : public test_suite_base
{
public:
test_suite (const char* name, Callable_T&& callable,
Args_T&&... arguments);
virtual ~test_suite () override;
virtual void
run (void) override;
protected:
Callable_T&& callable_;
std::tuple<Args_T...> arguments_;
};
template <typename Callable_T, typename... Args_T>
test_suite<Callable_T, Args_T...>::test_suite (const char* name,
Callable_T&& callable,
Args_T&&... arguments)
: test_suite_base{ name }, callable_{ std::forward<Callable_T> (
callable) },
arguments_{ std::forward<Args_T> (arguments)... }
{
runner.register_test_suite (this);
}
template <typename Callable_T, typename... Args_T>
test_suite<Callable_T, Args_T...>::~test_suite ()
{
}
template <typename Callable_T, typename... Args_T>
void
test_suite<Callable_T, Args_T...>::run (void)
{
current_test_suite = this;
begin_test_suite ();
std::apply (callable_, arguments_);
end_test_suite ();
}
完整代码可从 GitHub。
该类实例化为:
static void
ts_args (int iv, double fv)
{
using namespace micro_os_plus::micro_test_plus;
test_case ("args", [&] {
expect (eq (iv, 42)) << "iv is 42";
expect (eq (fv, 42.0)) << "fv is 42.0";
});
}
static micro_os_plus::micro_test_plus::test_suite ts_3
= { "Args const", ts_args, 42, 42.0 };
static int n = 42;
static micro_os_plus::micro_test_plus::test_suite ts_4
= { "Args vars", ts_args, n, 42.0 };
第一次调用(使用常量)没问题;第二次调用(使用变量)失败:
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/tests/src/sample-test.cpp:320:51: error: no viable constructor or deduction guide for deduction of template arguments of 'test_suite'
static micro_os_plus::micro_test_plus::test_suite ts_4
^
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/include/micro-os-plus/test-suite.h:204:5: note: candidate function [with Callable_T = void (int, double), Args_T = <int, double>] not viable: expects an rvalue for 3rd argument
test_suite (const char* name, Callable_T&& callable,
^
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/include/micro-os-plus/test-suite.h:201:9: note: candidate function template not viable: requires 1 argument, but 4 were provided
class test_suite : public test_suite_base
我还尝试使用 test_suite
使用显式类型,但没有帮助。
所以事情比我想象的要复杂,而且似乎使用这种语法只有右值应该匹配(尽管GCC不太严格)。
回顾一下,问题是如何捕获带有可变参数的通用调用(在我的例子中,通过静态构造函数在测试套件自动注册期间发生),存储所有内容并在稍后执行它(当测试套件执行部分时)的测试)。
I have a test framework where I need to capture the call to a generic function (a test suite) and execute it at a later time.
For this I use a class template with a parameter pack and I store the arguments in a tuple.
Everything builds and runs fine with GCC 10 and GCC 11, but fails with clang.
The code looks like this:
template <typename Callable_T, typename... Args_T>
class test_suite : public test_suite_base
{
public:
test_suite (const char* name, Callable_T&& callable,
Args_T&&... arguments);
virtual ~test_suite () override;
virtual void
run (void) override;
protected:
Callable_T&& callable_;
std::tuple<Args_T...> arguments_;
};
template <typename Callable_T, typename... Args_T>
test_suite<Callable_T, Args_T...>::test_suite (const char* name,
Callable_T&& callable,
Args_T&&... arguments)
: test_suite_base{ name }, callable_{ std::forward<Callable_T> (
callable) },
arguments_{ std::forward<Args_T> (arguments)... }
{
runner.register_test_suite (this);
}
template <typename Callable_T, typename... Args_T>
test_suite<Callable_T, Args_T...>::~test_suite ()
{
}
template <typename Callable_T, typename... Args_T>
void
test_suite<Callable_T, Args_T...>::run (void)
{
current_test_suite = this;
begin_test_suite ();
std::apply (callable_, arguments_);
end_test_suite ();
}
The full code is available from GitHub.
The class is instantiated with:
static void
ts_args (int iv, double fv)
{
using namespace micro_os_plus::micro_test_plus;
test_case ("args", [&] {
expect (eq (iv, 42)) << "iv is 42";
expect (eq (fv, 42.0)) << "fv is 42.0";
});
}
static micro_os_plus::micro_test_plus::test_suite ts_3
= { "Args const", ts_args, 42, 42.0 };
static int n = 42;
static micro_os_plus::micro_test_plus::test_suite ts_4
= { "Args vars", ts_args, n, 42.0 };
The first call (using constants) is fine; the second call (with a variable) fails with:
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/tests/src/sample-test.cpp:320:51: error: no viable constructor or deduction guide for deduction of template arguments of 'test_suite'
static micro_os_plus::micro_test_plus::test_suite ts_4
^
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/include/micro-os-plus/test-suite.h:204:5: note: candidate function [with Callable_T = void (int, double), Args_T = <int, double>] not viable: expects an rvalue for 3rd argument
test_suite (const char* name, Callable_T&& callable,
^
/Users/ilg/My Files/WKS Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/include/micro-os-plus/test-suite.h:201:9: note: candidate function template not viable: requires 1 argument, but 4 were provided
class test_suite : public test_suite_base
I also tried to use explicit types with test_suite<void (int, double), int, double>
, but it did not help.
So things are more complicated than I thought, and it seems that with this syntax only rvalues are expected to match (although GCC is less strict).
To recap, the question is how to capture a generic call with variable arguments (which in my case happens during test suite auto-registration, via static constructors), store everything and execute it at a later moment (when the test suite is executed part of the test).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过我的测试的解决方案是仅使构造函数成为模板,并将延迟调用存储为使用
std :: bind()
创建的函数:参数包已正确捕获并允许常量,变量,参考和指针:
A solution that passed my tests was to make only the constructor a template, and store the deferred call as a function created with
std::bind()
:The parameter pack is correctly captured and allows constants, variable, references and pointers: