c++11 - 类型选择中的 C++ 模板元编程问题

标签 c++11 boost

下面的代码说明了我的问题

#include <type_traits>
#include <limits>
#include <cstdint>
#include <boost/mpl/if.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>

/////////////////////////////////////////////////////////////////
// safe_signed_range

template <
    std::intmax_t MIN,
    std::intmax_t MAX
>
struct safe_signed_range {
};

/////////////////////////////////////////////////////////////////
// safe_unsigned_range

template <
    std::uintmax_t MIN,
    std::uintmax_t MAX
>
struct safe_unsigned_range {
};

template<class T, class U>
using calculate_max_t = typename boost::mpl::if_c<
    std::numeric_limits<T>::is_signed
    || std::numeric_limits<U>::is_signed,
    std::intmax_t,
    std::uintmax_t
>::type;

template<typename T, typename U>
struct test {

    typedef calculate_max_t<T, U> max_t;
    static_assert(std::is_same<max_t, std::intmax_t>::value, "unexpected value for max_t");
    static_assert(std::is_signed<max_t>::value, "check parameter");

/*
    typedef typename boost::mpl::if_c<
        std::is_signed<max_t>::value,
        safe_signed_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()>,
        safe_unsigned_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()>
    >::type type;
*/

    typedef typename boost::mpl::eval_if_c<
        std::is_signed<max_t>::value,
        boost::mpl::identity<safe_signed_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()> >,
        // error shows up here
boost::mpl::identity<safe_unsigned_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()> >
    >::type type;
};

test<int, int> t1;
//test<int, unsigned> t2;
//test<unsigned, int> t3;
//test<unsigned, unsigned> t4;

int main(){
    return 0;
}

Clang 编译器错误显示为

/Users/robertramey/WorkingProjects/safe_numerics/test/test_z.cpp:116:50: Non-type template argument evaluates to -9223372036854775808, which cannot be narrowed to type 'std::uintmax_t' (aka 'unsigned long')

这看起来 Boost Mpl 没有选择正确的类型。首先,我怀疑(实际上仍然怀疑)if 的所有参数都被扩展,所以我更改为使用 eval_if 但仍然遇到问题。我包含 static_assert 来检查参数,并可以通过最简单的测试使其失败 - 尽管它在所有组合上都会失败。如果有人可以向我解释我的错误,我将不胜感激。

最佳答案

问题是您正在实例化一个对于当前类型的 safe_unsigned_range 无效的模板(无论 boost::mpl::identity)。解决方案是根据传递给 boost::mpl::eval_if_c 的 bool 谓词推迟模板实例化。

为此,我们必须首先为两种范围类型编写我们自己的 identity 版本:

template<typename Integer, Integer Top, Integer Bottom>
struct defer_unsigned_lazily {
    using type = safe_unsigned_range<Top, Bottom>;
};

template<typename Integer, Integer Top, Integer Bottom>
struct defer_signed_lazily {
    using type = safe_signed_range<Top, Bottom>;
};

其工作方式是,在我们执行 typename X::type 本质上为我们提供诸如 boost::mpl::identity 之类的惰性语义之前,实例化不会发生.

然后我们像这样更改 typedef:

using limits = std::numeric_limits<max_t>;
typedef typename boost::mpl::eval_if_c<
    std::is_signed<max_t>::value, 
    defer_signed_lazily<max_t, limits::min(), limits::max()>, 
    defer_unsigned_lazily<max_t, limits::min(), limits::max()>
>::type type;

之后,它应该在 Clang 和 GCC 上按预期编译。

Demo

关于c++11 - 类型选择中的 C++ 模板元编程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31329593/

相关文章:

c++ - boost::bind 与重载函数?

c++ - 动态编译时混合

c++ - OS X 上 std::enable_shared_from_this<> 的编译错误

c++ - 链接到 Boost 线程库失败

c++ - Boost 库中 do_accept 函数结束时不会调用listener::on_accept 函数

c++ - 使用具有不同编译器版本的 boost 库

c++ - 如何使用具有不同参数的函数作为函数参数

c++ - Boost.Spirit语法问题

c++ - 默认析构函数 nothrow

c++ - 使用 asio 时双重释放或损坏