如何将作为模板类传递的函数转换为constexpr可调用(C++,模板元编程)?

How to take a function passed as a template class and turn it into a constexpr callable (C++, template meta-programming)?

提问人:ajl123 提问时间:7/20/2023 最后编辑:ajl123 更新时间:7/20/2023 访问量:57

问:

我有一个外部函数,它通过模板参数作为类传递给另一个类。我想在 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.
C++ 模板 template-元编程

评论

0赞 Amolgorithm 7/20/2023
你说的是什么意思:我有一个作为类传递的外部函数
0赞 ajl123 7/20/2023
@Amolgorithm,我编辑了这个问题,以提供如何初始化类的示例。
0赞 Jarod42 7/20/2023
似乎你构造了一个布尔元组,那为什么不呢?static_assert(F{}(std::tuple((std::type_identity<Levels>(), false)...)));

答:

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
这不起作用,因为我链接的编译器错误无法识别为 constexprFerror: 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