1

在 C++ 中,我正在尝试编写类似于 boost-mp11 的东西mp_for_each。但是,虽然mp_for_each总是为T给定中的每个调用提供的函数mp_list<Ts...>,但我试图提出一个解决方案,一旦对函数的运行时调用false在 if 语句中产生评估为的值,就停止遍历。

查看实现mp_for_each和使用示例:

在 GitHub 上实现

Boost 参考手册中的使用示例

显然, 的实现mp_for_each设法将函数参数作为常量表达式传递,从而使用户能够在需要常量表达式的地方应用它。虽然我采用了一种结合模板尾递归的不同方法,但我希望函数参数也可以作为常量表达式传递。然而,GCC 抱怨它“不是一个常量表达式”。

我的代码如下所示:

#include <cstdlib>
#include <iostream>
#include <typeinfo>
#include <utility>
#include <boost/mp11.hpp>

template<std::size_t T_counter>
struct WhileGreaterZero
{
    template<typename T_Function>
    constexpr WhileGreaterZero(T_Function&& function)
    {
        if (function(T_counter))  // pass function argument
            WhileGreaterZero<T_counter - 1>(std::forward<T_Function>(function));
    }
};

template<>
struct WhileGreaterZero<0>
{
    template<typename T_Function>
    constexpr WhileGreaterZero(T_Function&&) {}
};

int main()
{
    using boost::mp11::mp_at_c;
    using boost::mp11::mp_list;
    using boost::mp11::mp_size;

    using Types = mp_list<bool, int, double>;

    WhileGreaterZero<mp_size<Types>::value - 1>(
        [](auto counter) {  // function parameter
            using Type = mp_at_c<Types, counter>;

            if (typeid(Type) == typeid(int))
                return false;

            return true;
        }
    );
}

使用 g++ 7.4.0 编译时,遇到以下错误(按我的口味格式化):

$ g++ -std=c++17 -I/path/to/boost

wgz.cpp:
    In substitution of ‘
        template<
            class L,
            long unsigned int I
        >
        using mp_at_c =
            typename boost::mp11::detail::mp_if_c_impl<
                (I < typename boost::mp11::detail::mp_size_impl<L>::type:: value),
                boost::mp11::detail::mp_at_c_impl<L, I>,
                void
            >::type::type
        [
            with L = boost::mp11::mp_list<bool, int, double>;
            long unsigned int I = counter
        ]
    ’:

wgz.cpp:42:49:
    required from ‘
        main()::<lambda(auto:1)>
        [with auto:1 = long unsigned int]
    ’

wgz.cpp:14:21:
    required from ‘
        constexpr WhileGreaterZero<T_counter>::WhileGreaterZero(T_Function&&)
        [
            with T_Function = main()::<lambda(auto:1)>;
            long unsigned int T_counter = 2
        ]
    ’

wgz.cpp:49:5:
    required from here

wgz.cpp:42:49:
    error: ‘counter’ is not a constant expression
             using Type = mp_at_c<Types, counter>;
                                                 ^
wgz:42:49:
    note: in template argument for type ‘long unsigned int’

为什么counter在我的代码中不被视为常量表达式?在这方面,mp11 的代码和我的代码之间的关键区别是什么?

4

2 回答 2

2

改变

function(T_counter)

function(std::integral_constant< std::size_t, T_counter >{})

function参数内不是编译时值。但是一个integral_constant不是编译时间值的值可以转换为一个整数,并且该整数一个编译时间常数,因为它不依赖于this.

一个相关的技巧是:

template<std::size_t...Is>
constexpr auto indexes( std::index_sequence<Is...> ={} ) {
  return std::make_tuple( std::integral_constant<std::size_t, Is>{}... );
}

那么你可以这样做:

template<std::size_t N, class F>
void While( F&& f ) {
  std::apply( [&](auto...Is) {
    (f( Is ) && ...);
  }, indexes( std::make_index_sequence<N>{} ) );
}

活生生的例子,没有递归。

于 2020-02-07T20:30:41.773 回答
0

lambda 的参数是函数的参数,它的值在编译时不传递。至少这条线格式不正确:

 using Type = mp_at_c<Types, counter>;

您必须等待模板 lambda 或实现您自己的仿函数

于 2020-02-07T20:19:18.273 回答