std 类专业化 - 满足原始 std::array 模板的标准库要求

Ted*_*gmo 12 c++ template-specialization language-lawyer stdarray

在为std::array 定义专门化是否安全std::array中,提问者询问专门化具有昂贵的默认构造函数的程序定义类型是否安全。目标是std::array使用廉价的方法来初始化 中的所有元素构造函数而不是默认构造函数来初始化 中的所有元素。

我现在并不质疑这个设计。我很好奇这种可能性,对于这个问题,我建议在聚合初始化时使用大括号省略,定义一个内部类并通过标签使用特殊的构造函数:

namespace foo {
struct cheap_tag_t {};
inline constexpr cheap_tag_t cheap_tag;

class bar {
public:
    inline bar() { std::cout << "expensive ctor\n"; }
    inline bar(int) { std::cout << "int ctor\n"; }
    inline bar(cheap_tag_t) { std::cout << "cheap ctor\n"; }
};
}  // namespace foo
Run Code Online (Sandbox Code Playgroud)
template <std::size_t N>
    requires (N != 0)     // let the standard array take care of N==0
struct std::array<foo::bar, N> {
    struct inner_array {
        foo::bar data[N];
    };

    inner_array m_data{
        []<std::size_t... I>(std::index_sequence<I...>) -> inner_array {
            return {(void(I), foo::cheap_tag)...};
        }(std::make_index_sequence<N>())
    };

    // ... fully compliant member functions ...
};
Run Code Online (Sandbox Code Playgroud)

我在标准中找不到任何禁止这种奇怪的专业化的内容。我说这很奇怪,因为对于最终用户来说,它有一个意想不到的功能,如下所示:

std::array<foo::bar, 0> b0;    // not using the specialization at all
std::array<foo::bar, 2> b1;    // cheap ctor
std::array<foo::bar, 2> b2{};  // cheap ctor
std::array<foo::bar, 2> b3{1}; // one "int ctor" + one "expensive ctor" (surprised user)
Run Code Online (Sandbox Code Playgroud)

关于语言律师问题:

  • 鉴于专业化的其余部分将满足原始std::array模板的标准库要求,专业化的上述部分是否符合标准1, 2

1. 我(试图)阅读的“标准”是 C++23 草案。namespace.std/2

除非明确禁止,否则程序可以将任何标准库类模板的模板专业化添加到命名空间,std前提是
(a)添加的声明依赖于至少一种程序定义的类型,并且
(b)专业化满足原始库的标准库要求模板。

如果您知道的早期或未来标准对我的问题有不同的答案,请随时提及。不需要得到可接受的答案。

2. 如果专业化的上述部分根据“标准”是可以的,但您发现未来存在其他问题,使其难以/不可能满足要求,也请随时提及。再说一遍,不是必需的。

use*_*522 6

您的专业不能以下列方式使用:

struct anyconv {
    template<typename T>
    operator T() { return T(); }
};

std::array<foo::bar, 2> x = {anyconv{}, anyconv{}};
Run Code Online (Sandbox Code Playgroud)

但是,anyconv可以隐式转换为,因此根据[array.overview]/2foo::bar中的要求,应该可以使用 2 个类型为 的初始值设定项子句进行列表初始化。std::array<foo::bar, 2>anyconv