我設計了一個更簡單的包裝類,它向物件添加標簽,目的是隱式轉換/能夠替換包裝的物件。
#include <string>
#include <type_traits>
#include <utility>
template < typename T, typename Key = std::string >
class myTag{
T val;
public:
Key key;
template < typename... Args,
typename = typename std::enable_if< std::is_constructible< T, Args... >::value >::type >
myTag(Args&&... args) :
val(std::forward< Args >(args)...) {
std::cout << "forward ctor" << std::endl;
}
myTag(const myTag& other) :
key(other.key), val(other.val) {
std::cout << "copy ctor" << std::endl;
}
myTag(myTag&& other):
key(other.key), val(other.val) {
std::cout << "move ctor" << std::endl;
}
operator T&() { return val; }
operator const T&() const { return val; }
};
int main(int argc, char const *argv[]) {
myTag< float > foo(5.6); // forward ctor
myTag< float > bar(foo); // forward ctor
return 0;
}
但是,我無法正確宣告和定義復制/移動建構式。我宣告了一個泛型建構式多載模板,該模板將其引數轉發給底層型別,只要這樣的構造是可能的。但是,由于隱式轉換運算子,它捕獲 的每個實體化myTag,有效地隱藏復制/移動建構式。
非默認復制/移動語意的重點是復制/移動鍵值與使用建構式模板默認初始化它。
如何讓編譯器更喜歡/優先考慮顯式復制/移動建構式與泛型多載?是否有任何額外的 SFINAE 檢查替代方法is_constructible<>可以避免隱式轉換?
編輯:我應該補充一點,我正在尋找 C 14 解決方案。
uj5u.com熱心網友回復:
它不會隱藏復制和移動建構式。在某些情況下,它只是在多載決議中擊敗了它們。
- 如果傳遞 a
myTag<float>&,則使用轉發建構式。 - 如果傳遞 a
const myTag<float>&則使用復制建構式。 - 如果傳遞 a
myTag<float>&&,則使用移動建構式。 - 如果傳遞 a
const myTag<float>&&,則使用轉發建構式。
復制和移動建構式不是模板,因此它們將戰勝具有相同簽名的模板。但是在推匯出的簽名與復制和移動建構式不同的情況下,轉發建構式可以更好地匹配。
處理此問題的慣用方法是根據引數的衰減型別從考慮中洗掉轉發建構式:
template <typename... Args>
constexpr myTag(Args&&... args)
requires
((sizeof...(Args) != 1 && std::is_constructible_v<T, Args...>) ||
(sizeof...(Args) == 1 && std::is_convertible_v<Args..., T> && !std::is_same_v<myTag, std::decay_t<Args>...>))
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/380313.html
