提问人:ajl123 提问时间:7/20/2023 最后编辑:ajl123 更新时间:7/20/2023 访问量:57
如何将作为模板类传递的函数转换为constexpr可调用(C++,模板元编程)?
How to take a function passed as a template class and turn it into a constexpr callable (C++, template meta-programming)?
问:
我有一个外部函数,它通过模板参数作为类传递给另一个类。我想在 constexpr 成员函数中调用该外部函数,并静态断言其输出值。代码如下所示,我在其中注释掉了该行:static_assert(F{}(f_args) == false);
其他一切都有效,在编译时构造。我可以使用任何C++14或更高版本。f_args
我想使用在模板递归末尾构造的f_args
来评估函数类型 F
,这需要我获取模板参数 F
并将其转换为可调用的 constexpr 内容。我该怎么做?
template <class F, class IK, class PK, class Levels, class Is>
class Coiterate;
template <class F, class IK, class PK, class... Levels, class... Is>
class Coiterate<F, IK, PK, std::tuple<Levels...>, std::tuple<Is...>>
{
private:
std::tuple<Levels&...> const m_levelsTuple;
F const m_comparisonHelper;
public:
explicit inline Coiterate(
F f,
Levels&... levels)
: m_levelsTuple(std::tie(levels...))
, m_comparisonHelper(f)
{
// run a compile-time validation
validate_boolean_args();
}
// Assume this work as expected. A tuple of booleans corresponding to each level
static constexpr auto ordered_mask_tuple = std::make_tuple(is_level_ordered<Levels>()...);
template <std::size_t I, typename... Args>
constexpr void validate_boolean_helper(std::tuple<Args...> f_args)
{
// Check if the current recursion depth (I) is less than the number of elements in Mask.
if constexpr (I < sizeof(ordered_mask_tuple))
{
validate_boolean_helper<I + 1, Args...>(std::tuple_cat(f_args, std::tuple<bool>(false)));
}
else
{
// When we reach the end of recursion (base case), call the function object F with the constructed boolean arguments.
static_assert(sizeof...(Args) == sizeof...(Levels), "Number of arguments must be equal to number of levels");
// XXX: This line results in the following errors.
// static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
}
}
constexpr void validate_boolean_args()
{
validate_boolean_helper<0>(std::tuple<>());
}
如何初始化类的伪代码示例Coiterate
// this is a function defined by the user
auto fn = [](std::tuple<bool, bool, bool, bool> t) constexpr
{ return (std::get<0>(t) || std::get<2>(t)) || (std::get<1>(t) || std::get<3>(t)); };
// the function is passed as a template parameter and as an argument to the constructor
Coiterate<std::function<bool(std::tuple<bool, bool, bool, bool>)>, ...>
coiter(fn, ...);
编译器错误示例
In file included from /Users/adam2392/Documents/xsparse/test/source/coiteration_test.cpp:17:
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: error: static_assert expression is not an integral constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^~~~~~~~~~~~~~~~~~~~
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<2UL, bool, bool>' requested here
validate_boolean_helper<I + 1, Args...>(std::tuple_cat(f_args, std::tuple<bool>(false)));
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<1UL, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:251:13: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<0UL>' requested here
validate_boolean_helper<0>(std::tuple<>());
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:206:13: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_args' requested here
validate_boolean_args();
^
/Users/adam2392/Documents/xsparse/test/source/coiteration_test.cpp:37:9: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::Coiterate' requested here
coiter(fn, s1, s2);
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: note: non-literal type 'std::function<bool (std::tuple<bool, bool>)>' cannot be used in a constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: error: static_assert expression is not an integral constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^~~~~~~~~~~~~~~~~~~~
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<3UL, bool, bool, bool>' requested here
validate_boolean_helper<I + 1, Args...>(std::tuple_cat(f_args, std::tuple<bool>(false)));
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<2UL, bool, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<1UL, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:251:13: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<0UL>' requested here
validate_boolean_helper<0>(std::tuple<>());
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:206:13: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_args' requested here
validate_boolean_args();
^
/Users/adam2392/Documents/xsparse/test/source/coiteration_test.cpp:83:9: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::Coiterate' requested here
coiter(fn, s1, s2, s3);
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: note: non-literal type 'std::function<bool (std::tuple<bool, bool, bool>)>' cannot be used in a constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: error: static_assert expression is not an integral constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^~~~~~~~~~~~~~~~~~~~
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<4UL, bool, bool, bool, bool>' requested here
validate_boolean_helper<I + 1, Args...>(std::tuple_cat(f_args, std::tuple<bool>(false)));
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<3UL, bool, bool, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<2UL, bool, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<1UL, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:251:13: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_helper<0UL>' requested here
validate_boolean_helper<0>(std::tuple<>());
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:206:13: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::validate_boolean_args' requested here
validate_boolean_args();
^
/Users/adam2392/Documents/xsparse/test/source/coiteration_test.cpp:144:9: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool, bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::singleton<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>>, std::tuple<>>::Coiterate' requested here
coiter(fn, s1, s2, s3, s4);
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: note: non-literal type 'std::function<bool (std::tuple<bool, bool, bool, bool>)>' cannot be used in a constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: error: static_assert expression is not an integral constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^~~~~~~~~~~~~~~~~~~~
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::hashed<std::tuple<>, unsigned long, unsigned long, xsparse::util::container_traits<std::vector, std::unordered_set, std::unordered_map>, xsparse::level_properties<false, false, false, false, false>>>, std::tuple<>>::validate_boolean_helper<2UL, bool, bool>' requested here
validate_boolean_helper<I + 1, Args...>(std::tuple_cat(f_args, std::tuple<bool>(false)));
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:235:17: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::hashed<std::tuple<>, unsigned long, unsigned long, xsparse::util::container_traits<std::vector, std::unordered_set, std::unordered_map>, xsparse::level_properties<false, false, false, false, false>>>, std::tuple<>>::validate_boolean_helper<1UL, bool>' requested here
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:251:13: note: in instantiation of function template specialization 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::hashed<std::tuple<>, unsigned long, unsigned long, xsparse::util::container_traits<std::vector, std::unordered_set, std::unordered_map>, xsparse::level_properties<false, false, false, false, false>>>, std::tuple<>>::validate_boolean_helper<0UL>' requested here
validate_boolean_helper<0>(std::tuple<>());
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:206:13: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::hashed<std::tuple<>, unsigned long, unsigned long, xsparse::util::container_traits<std::vector, std::unordered_set, std::unordered_map>, xsparse::level_properties<false, false, false, false, false>>>, std::tuple<>>::validate_boolean_args' requested here
validate_boolean_args();
^
/Users/adam2392/Documents/xsparse/test/source/coiteration_test.cpp:235:9: note: in instantiation of member function 'xsparse::level_capabilities::Coiterate<std::function<bool (std::tuple<bool, bool>)>, unsigned long, unsigned long, std::tuple<xsparse::levels::dense<std::tuple<>, unsigned long, unsigned long>, xsparse::levels::hashed<std::tuple<>, unsigned long, unsigned long, xsparse::util::container_traits<std::vector, std::unordered_set, std::unordered_map>, xsparse::level_properties<false, false, false, false, false>>>, std::tuple<>>::Coiterate' requested here
coiter(fn, dense_level, hash_level);
^
/Users/adam2392/Documents/xsparse/include/xsparse/level_capabilities/co_iteration.hpp:245:31: note: non-literal type 'std::function<bool (std::tuple<bool, bool>)>' cannot be used in a constant expression
static_assert(F{}(f_args) == false, "Function F should return false for the given arguments.");
^
4 errors generated.
答:
0赞
user10468397
7/20/2023
#1
如果你的意思只是通过模板参数调用constexpr函数,
可以做这样的事情:
#include <tuple>
template <class F>
class Eval {
private:
const F func_;
public:
inline constexpr
explicit Eval(F f) : func_(f) {
validate_bool_f(std::make_tuple<>());
}
template <class... Args>
constexpr void validate_bool_f(std::tuple<Args...> rhs) noexcept {
static_assert(F{}(rhs), "Function returned false");
}
};
int main(int,char**) {
constexpr auto f =
[]<typename... Args>(const std::tuple<Args...>& args)
{
return false;
};
;
Eval<decltype(f)> c(f);
}
将函数存储为 constexpr 变量,并使用 decltype 传递其类型。
评论
0赞
ajl123
7/20/2023
这不起作用,因为我链接的编译器错误无法识别为 constexprF
error: static_assert expression is not an integral constant expression
0赞
user10468397
7/20/2023
@ajl123 是的,它会像返回 false 一样表现。这段代码的要点是传递我之前说过的 constexpr 函数类型的方法,并将构造函数定义为 constexpr 构造函数。f
0赞
user10468397
7/20/2023
我可能误会了。我已经测试了这段代码,只有 C++20 clang,gcc 两者,而不是其他。您正在使用的是C++14吗?
0赞
ajl123
7/20/2023
构造函数必须是非 constexpr,因为它正在传入一些仅在运行时已知的对象。是的,我现在需要使用旧版本的C++,所以C++14将是理想的。
0赞
ajl123
7/21/2023
这也不适用于 C++17:godbolt.org/z/EqeY3nv6n
评论
static_assert(F{}(std::tuple((std::type_identity<Levels>(), false)...)));