众所周知,在 C++ 中,朋友的朋友不是(自动地)朋友。
然而,Clang 在 GCC 和 MSVC 的以下代码上有所不同:
class A {
public:
// forward declaration
class Inner2;
private:
class Inner1 {
char foo;
friend class Inner2;
};
public:
class Inner2 {
Inner1 i;
public:
bool operator==(Inner2 other) {
return i.foo == other.i.foo; // OK by GCC, Clang and MSVC++
}
friend bool operator!=(Inner2 a, Inner2 b) {
return a.i.foo != b.i.foo; // Clang accepts, GCC and MSVC++ reject
}
};
};
Run Code Online (Sandbox Code Playgroud)
代码:https …
尝试在以下代码中提取模板参数值:
template<std::size_t SIZE>
class Foo {};
template <template<std::size_t> class T, std::size_t K>
auto extractSize(const T<K>&) {
return K;
}
int main() {
Foo<6> f1;
Foo<13> f2;
std::cout << extractSize(f1) << std::endl;
std::cout << extractSize(f2) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
(作为问题的答案: 提取C++模板参数).
但是,有没有办法在不知道模板参数类型的情况下执行此操作.类似的东西(下面的代码不能编译......):
template <template<class SIZE_TYPE> class T, SIZE_TYPE K>
auto extractSize(const T<K>&) {
return K;
}
Run Code Online (Sandbox Code Playgroud)
编译错误:
error: unknown type name 'SIZE_TYPE'
template <template<class SIZE_TYPE> class T, SIZE_TYPE K>
^
Run Code Online (Sandbox Code Playgroud) C++17添加了[[nodiscard]]
.
C++20添加了[[nodiscard]]
onempty
方法的使用,例如——也许是为了避免用户与方法 clear 混淆(即意外调用empty()来清除向量)。vector::empty()
为什么 C++20 没有利用这个机会添加[[nodiscard]]
到unique_ptr::release
?
是否存在一种有效的合理场景,即在unique_ptr::release
不获取返回值的情况下进行调用?
以同样的方式避免用户混淆(如果这是添加[[nodiscard]]
到empty
方法的原因) - 名称release
总是非常混乱,听起来像,嗯......这里将发布一些东西。
添加[[nodiscard]]
可以在某种程度上解决这个名称问题。
[expr.unary.noexcept]的措辞在C++17 中发生了变化。
以前(n4140, 5.3.7 noexcept operator [expr.unary.noexcept]),我的重点是:
- 如果在潜在求值的上下文中表达式将包含,则 noexcept 运算符的结果为 false
(3.1) 对不具有非抛出异常规范 ([except.spec]) 的函数、成员函数、函数指针或成员函数指针的潜在求值调用,除非调用是常量表达式 ([ expr.const]) ...
现在1(7.6.2.6 noexcept 运算符 [expr.unary.noexcept]):
- 除非表达式可能抛出异常 ([except.spec]),否则noexcept 运算符的结果为真。
- 如果函数声明没有 noexcept 说明符,则该声明具有潜在的抛出异常说明,除非...
但是14.5(3)的除非列表未列出constexpr
,因此可能会抛出...
1 LF 在评论中添加的指向 C++17 n4659的链接。
constexpr int f(int i) { return i; }
std::cout << boolalpha << noexcept(f(7)) << std::endl;
int a = 7;
std::cout …
Run Code Online (Sandbox Code Playgroud) 尝试根据数组大小的有效性进行专业化:
// base template
template<int p, typename T = void>
struct absolute {
operator int () const { return 0; }
};
// positive case template
template<int p>
struct absolute<p, typename std::void_t<int[p]>> {
operator int () const { return p; }
};
// negative case template
template<int p>
struct absolute<p, typename std::void_t<int[-p]>> {
operator int () const { return -p; }
};
int main() {
std::cout << absolute<5>() << std::endl;
std::cout << absolute<-5>() << std::endl;
std::cout << absolute<0>() << std::endl; …
Run Code Online (Sandbox Code Playgroud) C++ 11将final
关键字引入了C++.
它可以在虚拟方法或类上使用.
声明一个类最终禁止任何类型的继承:public,protected和private.
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
Run Code Online (Sandbox Code Playgroud)
虽然禁止公共继承是合理的(例如,如果我的类没有虚拟析构函数,或者出于其他原因),为什么我应该禁止私有继承?
可能是因为如果只final
禁止公共继承,那它std::string
和std中的其他朋友会final
- 因为他们应该 - 因为没有虚拟的析构函数?
编辑:
Howard Hinnant已经回答了为什么标准集装箱不是最终的,但仍然有理由宣布一个班级决赛,但允许私人继承.
[1]
\n\n是否有任何情况不需要将p0593r6添加到 C++20 ( \xc2\xa7 6.7.2.11对象模型[intro.object] ) std::launder
,而需要 C++17 中的相同用例std::launder
,或者它们是完全正交?
[2]
\n\n[ptr::launder]规范中的示例是:
\n\nstruct X { int n; };\nconst X *p = new const X{3};\nconst int a = p->n;\nnew (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const\nconst int b = p->n; // undefined behavior\nconst int c = std::launder(p)->n; // OK\n
Run Code Online (Sandbox Code Playgroud)\n\n@Nicol Bolas在这个 SO 答案中给出了另一个例子,使用指向有效存储但类型不同的指针:
\n\n …这是在具有参考字段的类上放置 new的答案的后续。
调用std::vector<A>::data()
上型A
具有参考或常量字段,将指针返回到对象可通过原始向量通过放置新的,这将导致一个的const或参考场来改变原始对象将被替换,而仍然被另一指针管理,通过调用返回data()
。
例如:
struct A {
const int i = 0;
};
int main() {
std::vector<A> vec = {{1}, {2}};
auto ptr = vec.data();
std::cout << ptr[1].i << std::endl; // 2
vec.pop_back();
vec.push_back({3}); // placement new, inside
std::cout << ptr[1].i << std::endl; // 3
}
Run Code Online (Sandbox Code Playgroud)
C++17 试图通过引入来解决这些问题,std::launder
但后来同意虽然std::launder
可以解决其他问题,但它并没有真正解决上述用例的问题,如NB US042 中所述。
一些问题 - 对于C++20 之前的C++ 版本:
由于NB US042 …
虽然 aspan
可以从范围构造,string_view
但不能从字符范围构造。
因此,例如,需要以下代码:
// assume chars_span is a span of chars
std::cout << std::string_view(chars_span.data(), chars_span.size());
// or:
std::cout << std::string_view(chars_span.begin(), chars_span.end());
Run Code Online (Sandbox Code Playgroud)
而不是不支持的更简单的范围语法:
std::cout << std::string_view(chars_span);
Run Code Online (Sandbox Code Playgroud)
是否有理由没有string_view
接受一系列字符的构造函数,或者它只是被忽视或被认为不够重要?
在下面的两个模板函数中,我们尝试了更多的约束:
template<typename T>
concept SmallVar = (sizeof(T) <= sizeof(int));
void print(SmallVar auto t) { // 1
std::cout << t << std::endl;
}
void print(const auto& t) { // 2
std::cout << t << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
当使用 int 调用时,Clang 和 GCC 有所不同:
int main() {
print(6); // clang accepts and prefers 1, gcc sees here ambiguity
}
Run Code Online (Sandbox Code Playgroud)
哪一个是正确的?
代码: https: //godbolt.org/z/x71zjzoTa
c++ ×10
c++20 ×4
templates ×2
c++11 ×1
c++14 ×1
c++17 ×1
constexpr ×1
final ×1
friend ×1
friend-class ×1
function-templates-overloading ×1
noexcept ×1
stdlaunder ×1
string-view ×1
unique-ptr ×1