首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这是g++8的一个非常数条件?

为什么这是g++8的一个非常数条件?
EN

Stack Overflow用户
提问于 2019-06-01 17:48:43
回答 2查看 650关注 0票数 8

我有这个密码。这是一个数组(有点像std :: array),我可以在编译时使用它。也适用于编译时的循环。

代码语言:javascript
复制
#include <utility>
#include <memory>
#include <type_traits>

template<class F,
         std::size_t ... Is>
constexpr void __loop(F&& func, std::index_sequence<Is ...>) noexcept
{
    (func(std::integral_constant<std::size_t, Is>{}), ...);
}

template<std::size_t N,
         typename F>
constexpr void CONSTEXPR_LOOP(F&& func) noexcept
{
    __loop(std::forward<F>(func), std::make_index_sequence<N>());
}

template<typename T, std::size_t Size>
class StaticArray
{
    static_assert(std::disjunction_v<
                        std::is_default_constructible<T>,
                        std::is_nothrow_default_constructible<T>
                    >,
                  "Type must have a trivial constructor.");
public:
    constexpr StaticArray() noexcept;
    template<typename ... Args,
             std::enable_if_t<
                 std::conjunction_v<
                     std::is_same<T, Args>...
                     >
                 > * = nullptr
             >
    constexpr StaticArray(Args && ... list) noexcept;
    constexpr StaticArray(const StaticArray& a) = delete;
    constexpr StaticArray(StaticArray&& a) = delete;
    ~StaticArray() noexcept = default;

    constexpr StaticArray& operator=(const StaticArray& a) = delete;
    constexpr StaticArray& operator=(StaticArray&& a) = delete;

    constexpr const T& operator[](std::size_t i) const noexcept;
private:
    T _data[Size];
    std::size_t _capacity;
    std::size_t _count;

    template<typename Arg>
    constexpr void set_data(std::size_t i, Arg&& arg) noexcept;
    template<typename ... Args, std::size_t ... Indices>
    constexpr void unpack(std::index_sequence<Indices ...>, Args&& ... args) noexcept;
    template<typename ... Args>
    constexpr void create_indexes(Args&& ... args) noexcept;
};


template<typename T, std::size_t Size>
constexpr StaticArray<T, Size>::StaticArray() noexcept :
    _data{T{}},
    _capacity{Size},
    _count{0}
{
}

template<typename T, std::size_t Size>
template<typename ... Args,
         std::enable_if_t<
             std::conjunction_v<
                 std::is_same<T, Args>...
                 >
             > *
         >
constexpr StaticArray<T, Size>::StaticArray(Args&& ... list) noexcept :
    _data{T{}},
    _capacity{Size},
    _count{Size}
{
    static_assert(Size == sizeof ... (list), "Size of array not equal number of elements in the list");
    static_assert(std::conjunction_v<std::is_same<T, Args>... >, "Parameter must be the same type as StaticArray<T>.");
    create_indexes(std::forward<Args>(list) ...);
}

template<typename T, std::size_t Size>
template<typename Arg>
constexpr void StaticArray<T, Size>::set_data(std::size_t i, Arg&& arg) noexcept
{
    _data[i] = arg;
}

template<typename T, std::size_t Size>
template<typename ... Args, std::size_t ... Indices>
constexpr void StaticArray<T, Size>::unpack(std::index_sequence<Indices ...>, Args&& ... args) noexcept
{
    (set_data(Indices, args), ...);
}

template<typename T, std::size_t Size>
template<typename ... Args>
constexpr void StaticArray<T, Size>::create_indexes(Args&& ... args) noexcept
{
    unpack(std::make_index_sequence<Size>{}, std::forward<Args>(args)...);
}

template<typename T, std::size_t Size>
constexpr const T& StaticArray<T, Size>::operator[](std::size_t i) const noexcept
{
    return _data[i];
}


int main()
{
    constexpr StaticArray<unsigned, 10> array = {9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u};

    static_assert(array[0] == 9);
    static_assert(array[1] == 8);
    static_assert(array[2] == 7);
    static_assert(array[3] == 6);
    static_assert(array[4] == 5);
    static_assert(array[5] == 4);
    static_assert(array[6] == 3);
    static_assert(array[7] == 2);
    static_assert(array[8] == 1);
    static_assert(array[9] == 0);

    constexpr std::array<unsigned, 10> checker = {9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u};

    CONSTEXPR_LOOP<10>([&](auto i) constexpr {
        static_assert(array[i] == checker[i]);
    });

    return 0;
}

当我使用g++-8.3编译它时,我得到了以下错误:

代码语言:javascript
复制
.../main.cpp: In instantiation of ‘main()::<lambda(auto:1)> [with auto:1 = std::integral_constant<long unsigned int, 0>]’:
.../main.cpp:9:10:   required from ‘constexpr void __loop(F&&, std::index_sequence<Is ...>) [with F = main()::<lambda(auto:1)>; long unsigned int ...Is = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; std::index_sequence<Is ...> = std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9>]’
.../main.cpp:16:11:   required from ‘constexpr void CONSTEXPR_LOOP(F&&) [with long unsigned int N = 10; F = main()::<lambda(auto:1)>]’
.../main.cpp:149:6:   required from here
.../main.cpp:148:32: error: non-constant condition for static assertion
         static_assert(array[i] == checker[i]);
                       ~~~~~~~~~^~~~~~~~~~~
.../main.cpp:148:32: error: ‘__closure’ is not a constant expression

在花了一些时间了解问题所在之后,我决定使用g++-7.4编译这段代码。它编译成功,没有任何错误。Clang-6和g++-9给出了同样的结果,但是一旦我使用g++-8,我就会得到上面描述的错误。知道为什么会这样吗?

谢谢!

备注在线示例:https://godbolt.org/z/Ig4CCW

UPDATE我在将静态说明符添加到变量时在g++-8中编译了这段代码。它之所以有效,是因为:

在这里输入链接描述

如果变量存在,lambda表达式可以使用变量而不捕获变量。

  • 是一个非局部变量,或者具有静态或线程本地存储持续时间>(在这种情况下不能捕获该变量)。

但是,如果您查看下面的代码,您会注意到,从另一个函数调用的lambda由于某种原因没有在g++-8中通过引用和值捕获constexpr变量。其他编译器不报告任何错误。

代码语言:javascript
复制
template<typename F>
constexpr void call(F&& f)
{
    f();
}

int main()
{
    constexpr std::array<unsigned, 1> checker = {1u};
    call([&]() constexpr { static_assert(checker[0] == checker[0]); });
    static constexpr std::array<unsigned, 1> checker2 = {1u};
    call([]() constexpr { static_assert(checker2[0] == checker2[0]); });
    constexpr std::array<unsigned, 1> checker3 = {1u};
    call([=]() constexpr { static_assert(checker3[0] == checker3[0]); });

    return 0;
}

试试看

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-07 16:35:03

嗯,我认为这可能是g++8中的一个bug。Lambda不捕获constexpr变量,下面的代码非常清楚地说明了这一点:

代码语言:javascript
复制
template<typename F>
constexpr void call(F&& f)
{
    f();
}

int main()
{
    constexpr std::array<unsigned, 1> checker = {1u};
    call([&]() constexpr { static_assert(checker[0] == checker[0]); }); // compile error
    static constexpr std::array<unsigned, 1> checker2 = {1u};
    call([]() constexpr { static_assert(checker2[0] == checker2[0]); }); // OK!
    constexpr std::array<unsigned, 1> checker3 = {1u};
    call([=]() constexpr { static_assert(checker3[0] == checker3[0]); }); // compile error

    return 0;
}

我没有发现任何提到这个问题的地方,所以我真的认为这是g++8中的一个bug。

另外,我找到了三种避免此错误的解决方案。如果得到相同的错误,则必须执行以下三项中的一项:

  1. 将变量标记为static。Lambda不需要捕获就可以使用静态变量。
  2. 使用模板在结构中包装您的constexpr变量:
代码语言:javascript
复制
template<std::size_t Size, typename T, T ... ARGS>
struct ArrayWrapper
{
   static constexpr std::array<T, Size> value = {ARGS ...};
};

constexpr ArrayWrapper<10, unsigned,
    9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u> wrapper;
  1. 使用另一个编译器。g++-7g++-9clang编译时没有任何错误。
票数 0
EN

Stack Overflow用户

发布于 2019-06-01 18:25:14

参数,即使在constexpr函数中也不是constexpr

代码语言:javascript
复制
constexpr void f(std::size_t n) {
  static_assert(n == 42, "");  // not allowed.
}

来源:https://mpark.github.io/programming/2017/05/26/constexpr-function-parameters/

更新:来自评论

我被auto愚弄了。事实上,既然呼吁是在这里:

代码语言:javascript
复制
func(std::integral_constant<std::size_t, Is>{}), ...);

auto是一个std::integral_constant,它应该能工作

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56409068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档