std::apply和常量表达式?

9
我在 Wandbox 上尝试了以下代码:
#include <array>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <functional>
#include <utility>


int main()
{
    constexpr std::array<const char, 10> str{"123456789"};
    constexpr auto foo = std::apply([](auto... args) constexpr { std::integer_sequence<char, args...>{}; } , str);
    std::cout << typeid(foo).name();
}

编译器告诉我args...不是常量表达式,这是为什么?


7
除非在C++1z中有所改变,否则您不能拥有constexpr函数参数。也就是说,每个函数必须假设它可能被调用具有运行时参数,然后您的lambda表达式就没有意义了。 - krzaq
@krzaq 真遗憾... - Cu2S
3个回答

7

函数参数不能被标记为constexpr。因此,您不能在需要常量表达式的地方使用它们,例如非类型模板参数。

要实现您尝试进行的操作,需要基于模板参数进行某种编译时字符串处理。


5

您想要的可以在不使用std::apply的情况下完成:

#include <array>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <functional>
#include <utility>
#include <type_traits>

template <std::size_t N, class = std::make_index_sequence<N>>
struct iterate;

template <std::size_t N, std::size_t... Is>
struct iterate<N, std::index_sequence<Is...>> {
    template <class Lambda>
    constexpr auto operator()(Lambda lambda) {
        return lambda(std::integral_constant<std::size_t, Is>{}...);
    }
};

int main()
{
    constexpr std::array<const char, 10> str{"123456789"};
    constexpr auto foo = iterate<str.size()>{}([](auto... is) constexpr { return std::integer_sequence<char, str[is]...>{}; });
    std::cout << typeid(foo).name();
}

[live demo]


1
我认为这个是可以的。std::integral_constant拥有自己的constexpr operator T()重载,允许它在constexpr上下文中使用。或者我漏掉了什么吗? - W.F.
1
你关于整型常量的看法似乎是正确的。http://eel.is/c++draft/expr.prim.lambda#10和http://eel.is/c++draft/expr.prim.lambda#13表明你的代码完全没问题。 - krzaq
1
你甚至可以为它制作一个“工厂”,但目前 gcc 在这个链接中崩溃了 http://melpon.org/wandbox/permlink/JRvLX98vakSP1k2k。 - Tomilov Anatoliy
1
具体来说,auto const & 模板参数。如果稍微修改一下为 template< std::size_t size, char const (& value)[size] >,那么就没问题了,但是这样我需要手动提供 size 参数。 - Tomilov Anatoliy
1
@W.F. 我已经提交了这个错误,但是它的状态还没有被改为已解决。这个扩展程序相当老了。不知道是否有人提出过建议。 - Tomilov Anatoliy
显示剩余9条评论

4

所有constexpr函数必须在constexpr和非constexpr状态下都有效,即使标记为constexpr。

有一个提案用于将字符作为非类型模板参数传递的constexpr字面量。然后"hello"_bob可以直接扩展为参数包。

另一种方法是通过某种机制将std::integral_constant<T, t>传递给lambda,例如我的indexer。然后,即使变量不是constexpr,转换为T也是constexpr的。这对于将"hello"转换为序列没有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接