在以下示例中
template<auto V>
struct A {};
struct B {
constexpr B(int a) : value{a} {}
private:
int value{0};
};
int main() {
constexpr B b{0};
A<b> t2;
}
成员value
必须公开以使类型B
结构化,以将其用作A
的NTTP。
那么,没有带有私有成员的类型可以用作NTTP吗? 这是http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1907r1.html的真实意图吗?
答案 0 :(得分:4)
这是[P1907]的真实意图吗?
P1907的目的是正确指定模板参数上下文中两个值等效的含义。在本文之前,等价概念首先基于<=>
(P0732),然后基于==
(P1185),但使用这些比较运算符作为基础有很多问题(如本文所述)。
考虑指针。我们已经有很长时间的书写能力了:
template <char const*> struct X { };
在这里,如果指针X<p>
和X<q>
指向具有静态存储的同一对象,则p
和q
是相同类型持续时间或两个空指针(P1907还允许两个指针都成为最新指针,或者都可以指向同一子对象)。
现在,考虑一种类型:
struct S {
char const* b;
char const* e;
char const* c;
};
如何:
template <S> struct Y { };
工作吗?此类型具有所有公共成员,因此可以肯定地说它没有不变量-任何人都可以修改这些指针中的任何一个以指向任何内容。这样的规则是,如果Y<s1>
和Y<s2>
是相同的指针,并且s1.b
和s2.b
是s1.e
和s2.e
是相同的类型是相同的指针,并且s1.c
和s2.c
是相同的指针。所有三个成对都相同。
现在考虑一种类型:
class String {
private:
char const* begin_;
char const* end_;
char const* capacity_;
public:
constexpr String();
constexpr String(char const*);
constexpr String(String const&);
constexpr String& operator=(String const&);
constexpr ~String();
};
此类型具有私有成员,因此,它强制执行一些不变量-可能对“相同”的含义有不同的理解,而不仅仅是“其所有成员都是成对等效的”。确实,String
大致是std::string
的外观(忽略SSO),如果我们采用成员等效的方法,则会遇到以下情况:
template <String> struct Z { };
每次 Z<"hello"s>
都可能给出不同的类型-因为我们必须分配存储空间来容纳字符串,并且这些基础指针可能会有所不同。 P1907的一个无关紧要的驱动因素是,最终希望允许:
template <std::string> struct C;
C<"hello">
不仅在翻译单元中始终是同一类型,而且在所有翻译单元中都始终是同一类型。基于<=>
/ ==
的机制在这种情况下不起作用。而使std::string
可以作为非类型模板参数正常工作的唯一方法是拥有一种自定义机制,其中std::string
的作者指定等效项基于-情况下,我们甚至根本不会查看容量指针,它只是基于从begin_
到end_
的字符序列(而不是指针值,指向的值)。
该新机制尚不存在(作者暗示operator template
),因此在存在该新机制之前,有两种选择:
我们选择了选项2,使用“ all public”作为进行简单的,按成员等效的机制...,但要理解C ++ 23将具有这样的机制(例如operator template
)允许使用std::string
,std::vector<char>
,std::optional<int>
等类型的非类型模板参数。
答案 1 :(得分:-1)
答案很简单,但令人失望:C ++ 20不允许这样做。最终,c ++ 23将引入更广泛的解决方案...