Ser*_* F. 8 c++ lambda templates g++ c++17
我有这个代码。这是std :: array我可以在编译时使用的数组(有点像)。在编译时也进行循环。
#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;
}
Run Code Online (Sandbox Code Playgroud)
当我使用编译时g++-8.3,出现以下错误:
.../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
Run Code Online (Sandbox Code Playgroud)
在花了一些时间了解问题所在之后,我决定使用编译此代码g++-7.4。它编译成功,没有任何错误。Clang-6和g++-9我得到相同的结果,但是当我使用g ++-8时,我得到了上述错误。知道为什么会这样吗?
谢谢!
[注意]在线示例:https : //godbolt.org/z/Ig4CCW
[更新]我在g++-8向constexpr变量添加静态说明符时编译了此代码。之所以有效,是因为:
Lambda表达式可以使用变量而不捕获它,如果该变量
- 是非局部变量,或者具有静态或线程局部存储持续时间>(在这种情况下,无法捕获该变量)
但是,如果您看下面的代码,则会注意到从另一个函数调用的lambda出于某种原因未通过中的引用和值捕获constexpr变量g++-8。其他编译器不报告任何错误。
.../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
Run Code Online (Sandbox Code Playgroud)
嗯,我认为这可能是g++8. Lambda 不捕获 constexpr 变量,下面的代码非常清楚地演示了这一点:
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;
}
Run Code Online (Sandbox Code Playgroud)
我没有发现任何提及这个问题的信息,所以我真的认为这是g++8.
另外,我找到了三种解决方案来避免此错误。如果您遇到相同的错误,则必须执行以下三个操作之一:
static. Lambda 可以使用静态变量而无需捕获。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;
Run Code Online (Sandbox Code Playgroud)
g++-7,g++-9并clang编译它,没有任何错误。| 归档时间: |
|
| 查看次数: |
268 次 |
| 最近记录: |