我使用 NTTP(非类型模板参数)lambdastring_view在编译时将 a 存储到类型中:
template<auto getStrLambda>
struct MyType {
static constexpr std::string_view myString{getStrLambda()};
};
int main() {
using TypeWithString = MyType<[]{return "Hello world";}>;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这有效,并实现了我的主要目的。
我现在的问题是,为了使其更易于使用,我如何编写一个包装函数来为我创建 lambda?
我在想这样的事情:
// This helper function generates the lambda, rather than writing the lambda inline
consteval auto str(auto&& s) {
return [s]() consteval {
return s;
};
};
template<auto getStrLambda>
struct MyType {
static constexpr std::string_view myString{getStrLambda()};
};
int main() {
using TypeWithString = MyType<str("Hello world")>;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在 clang 上失败了,因为 lambda 不是结构化的,因为它需要捕获字符串:
error: type '(lambda at <source>:4:12)' of non-type template parameter is not a structural type
using TypeWithString = MyType<str("Hello world")>;
^
note: '(lambda at <source>:4:12)' is not a structural type because it has a non-static data member that is not public
return [s]() consteval {
^
Run Code Online (Sandbox Code Playgroud)
如果变量被初始化为常量表达式( source ),则 lambda 可以使用变量而不捕获它,那么如何定义一个函数来在编译时参数化此 lambda 返回值?
这是CWG2542。
在解决相关问题之前,GCC 和 Clang 在接受或拒绝该程序方面实际上并没有错误。lambda 的类型只有一个类型为 的数据成员char[12],该成员可以是公共的或私有的。看来 Clang 将他们视为私人成员。
但现在,在 CWG2542 之后,捕获 lambda 不能具有结构类型,因此您必须做其他事情。
显而易见的解决方案是显式写出闭包类型,确保数据成员始终是公共的:
consteval auto str(auto&& s) {
static_assert(std::is_array_v<std::remove_reference_t<decltype(s)>>);
return [&]<std::size_t... I>(std::index_sequence<I...>) {
struct {
std::remove_cvref_t<decltype(s)> value;
consteval std::decay_t<decltype(s)> operator()() const {
return value;
}
} functor{{std::forward<decltype(s)>(s)[I]...}};
return functor;
}(std::make_index_sequence<std::extent_v<std::remove_reference_t<decltype(s)>>>{});
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,对于相同长度的字符串,它将具有相同的类型,因此MyType<str("xyz")>在一个翻译单元中将与另一个翻译单元中的名称相同MyType<str("xyz")>,因为它存储一个数组。
str("string literal")作为函数调用并返回“没有任何捕获”的东西的目标是不可能的,因为函数参数auto&& s在常量表达式中不可用。特别是,您无法将其转换为指针,也无法访问其任何项目。
您还可以使用str类型并跳过函数的步骤:
template<typename T>
struct str;
template<typename T, std::size_t N>
struct str<T[N]> {
T value[N];
constexpr str(const str&) = default;
consteval str(const T(& v)[N]) : str(std::make_index_sequence<N>{}, v) {}
consteval auto operator()() const {
return value;
}
private:
template<std::size_t... I>
consteval str(std::index_sequence<I...>, const T(& v)[N]) : value{ v[I]... } {}
};
template<typename T, std::size_t N>
str(const T(&)[N]) -> str<T[N]>;
Run Code Online (Sandbox Code Playgroud)
str("string literal")现在保存数组的结构类型在哪里。
| 归档时间: |
|
| 查看次数: |
720 次 |
| 最近记录: |