在使用 C 20 時,我遇到了一個奇怪的問題,我不確定這是由于 C 20 還處于起步階段而導致的編譯器缺陷,或者這是否是正確的行為。
問題是特定的約束函式要么沒有正確選擇,要么產生編譯錯誤——完全取決于定義的順序。
這發生在特定情況下:
- 建構式/解構式/成員函式受
requires, 和 - 此建構式/解構式/成員函式對于某些不滿足子句的實體化被
T隱式requires洗掉
例如,考慮這個基本naive_optional<T>實作:
template <typename T>
class naive_optional {
public:
naive_optional() : m_empty{}, m_has_value{false}{}
~naive_optional() requires(std::is_trivially_destructible_v<T>) = default;
~naive_optional() {
if (m_has_value) {
m_value.~T();
}
}
private:
struct empty {};
union {
T m_value;
empty m_empty;
};
bool m_has_value;
};
此代碼適用于諸如 的瑣碎型別naive_optional<int>,但無法實體化非瑣碎型別,例如naive_optional<std::string>由于隱式洗掉的解構式:
<source>:26:14: error: attempt to use a deleted function
auto v = naive_optional<std::string>{};
^
<source>:8:5: note: explicitly defaulted function was implicitly deleted here
~naive_optional() requires(std::is_trivially_destructible_v<T>) = default;
^
<source>:17:11: note: destructor of 'naive_optional<std::basic_string<char>>' is implicitly deleted because variant field 'm_value' has a non-trivial destructor
T m_value;
^
1 error generated.
Live Example
如果更改定義的順序以使受約束的函式低于不受約束的函式,則可以正常作業-但每次都選擇不受約束的函式:
...
~naive_optional() { ... }
~naive_optional() requires(std::is_trivially_destructible_v<T>) = default;
...
Live Example
我的問題最終是:這種行為是否正確——我在濫用requires嗎?如果這是正確的行為,是否有任何簡單的方法可以有條件地完成default一個本身不是模板的建構式/解構式/函式?我希望避免繼承基類實作的“傳統”方法。
uj5u.com熱心網友回復:
您的代碼是正確的,并且確實是支持此類事情的激勵示例(請參閱P0848,我是其中的作者之一)。Clang 還沒有實作這個特性(你可以在這里看到)。
gcc 和 msvc 都接受您的代碼。
請注意,您不再需要empty,union { T val; }在 C 20 中就足夠了,這要歸功于P1331。演示。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/457294.html
