对于模板类,
template <typename T>
struct Test {
T data;
static const Test constant;
};
Run Code Online (Sandbox Code Playgroud)
定义特殊类型的成员变量时没问题static constexpr:
template <>
inline constexpr Test<int> Test<int>::constant {42};
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/o4c4YojMf
static constexpr当直接从模板类定义成员而不实例化时,编译器的结果会有所不同:
template <typename T>
inline constexpr Test<T> Test<T>::constant {42};
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/M8jdx3WzM
GCC编译。
clang忽略constexpr定义中的说明符。
MSVC.../std:c++17效果很好,但/std:c++20由于重新定义而被拒绝。
在这个例子中,哪一个是正确的?为什么?
否则,如果 Ranges::disable_sized_range<std::remove_cv_t<T>> 为 false,则 size(t) 转换为其衰减类型,并且转换后的表达式有效且具有类似整数的类型,其中重载解析通过以下命令执行以下候选人:
void size(auto&) = delete;void size(const auto&) = delete;1
class Test {
friend size_t size(/*const*/ Test&) {
return 0;
}
};
int main() {
std::ranges::size(Test{});
// no matching function error when adding the `const` qualifier
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/79e5vrKrT
一般来说,方法size不需要像std::size.
为什么会有这样的限制呢std::ranges::size?(好像只有非会员版才能执行。)
相关问题:
#include <type_traits>
#include <vector>
struct A {
A();
};
static_assert(std::is_convertible_v<double, A> == false);
static_assert(std::is_convertible_v<A, double> == false);
void func(std::vector<double> values);
void func(std::vector<A> as);
int main() {
func({ 4.2 });
}
Run Code Online (Sandbox Code Playgroud)
显然,double和A不能相互隐式转换。所以我觉得void func(std::vector<double>)应该叫。
但不同编译器的结果是不同的: https://godbolt.org/z/c1hW47f4c
GCC 无法编译:
<source>: In function 'int main()':
<source>:14:9: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
14 | func({ 4.2 });
| ~~~~^~~~~~~~~
<source>:10:6: note: candidate: 'void func(std::vector<double>)'
10 | void func(std::vector<double> …Run Code Online (Sandbox Code Playgroud) template<typename Integral>
struct IntegralWrapper {
Integral _value;
IntegralWrapper() = default;
IntegralWrapper(Integral value)
: _value(value) {}
operator Integral() const {
return _value;
}
operator bool() const = delete;
};
int main() {
IntegralWrapper<int> i1, i2;
i1 * i2;
}
Run Code Online (Sandbox Code Playgroud)
gcc 编译成功,但 MSVC 和 clang 编译失败,错误overloaded operator '*' is ambiguous。问题来自于显式删除operator bool。
https://godbolt.org/z/nh6M11d98
哪一方(gcc 或 clang/MSVC)是正确的?为什么?
c++ operator-overloading language-lawyer implicit-conversion
一个相对的问题,但我想要一个没有任何运行时开销的解决方案。(所以构建一个新的pair或使用std::variant不是答案)
由于潜在的模板专业化,参考文献已经说过pair<K, V>和pair<const K, V>不相似,这意味着简单的reinterpret_cast会触发未定义的行为。
auto p1 = pair<int, double>{ 1, 2.3 };
auto& p2 = reinterpret_cast<pair<const int, double>&>(p1); // UB!
Run Code Online (Sandbox Code Playgroud)
类型双关union在 C 中工作得很好,但在 C++ 中并不总是合法的:
但有一个例外(与 C 中的行为一致?):
由于KeyandValue可能不是并且standard-layout可能有non-trivial析构函数,因此这里的类型双关似乎是不可能的,尽管pair<Key, Value>和的成员pair<const Key, Value>可以共享相同的生命周期(当然带有对齐断言)。
template <typename Key, typename Value>
union MapPair {
using TrueType = pair<Key, Value>;
using …Run Code Online (Sandbox Code Playgroud) using T = decltype(std::same_as<int, double>)
我在VS2019上试过这个。事实证明T = bool。
这是由标准定义的,还是只是特定编译器的属性?我还没有找到任何有关它的官方信息.. https://en.cppreference.com/w/cpp/concepts
例如,比较的std::less定义为模板结构
template< class T = void >
struct less;
Run Code Online (Sandbox Code Playgroud)
Whilestd::compare_three_way被定义为一个普通的结构体,它operator()是一个模板函数。(来自 MSVC 的代码)
struct compare_three_way {
template <class _Ty1, class _Ty2>
requires three_way_comparable_with<_Ty1, _Ty2> // TRANSITION, GH-489
constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
noexcept(noexcept(_STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right))) /* strengthened */ {
return _STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right);
}
using is_transparent = int;
};
Run Code Online (Sandbox Code Playgroud)
那么为什么不是std::compare_three_way模板结构呢?
template <class _Ty1, class _Ty2>
requires three_way_comparable_with<_Ty1, _Ty2>
struct compare_three_way {
constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) …Run Code Online (Sandbox Code Playgroud) 在 C/C++ 中,
复合赋值运算符将简单赋值运算符与另一个二元运算符组合在一起。复合赋值运算符执行附加运算符指定的操作,然后将结果分配给左操作数。例如,复合赋值表达式,如
expression1 += expression2可以理解为
expression1 = expression1 + expression2然而,复合赋值表达式并不等同于扩展版本,因为复合赋值表达式只计算 expression1 一次,而扩展版本计算 expression1 两次:在加法运算和赋值运算中。
(引自Microsoft Docs)
例如:
i+=2;,i将直接修改而不创建任何新对象。i=i+2;,i首先会创建一个副本。复制的一个将被修改,然后被分配回i. i_copied = i;
i_copied += 2;
i = i_copied;
Run Code Online (Sandbox Code Playgroud)
如果没有编译器的任何优化,第二种方法将构造一个无用的实例,从而降低性能。
在 C# 中,+=不允许重载类似运算符。并且所有像or一样的简单类型都声明为(这是否意味着 C# 中的所有结构实际上都是不可变的?)。intdoublereadonly struct
我不知道在C#,是有一定的表达力对象被修改(至少对于简单类型)直接,而不被创建的任何无用实例。
而且,是否有可能在C#-compiler优化表达x=x+y到x+=y不如预期,如果有一个从构造函数和deconstructors无副作用。