[英]C++ std::vector initializer_list overload ambiguity (g++/clang++)
請考慮以下代碼:
#include <vector>
#define BROKEN
class Var {
public:
#ifdef BROKEN
template <typename T>
Var(T x) : value(x) {}
#else
Var(int x) : value(x) {}
#endif
int value;
};
class Class {
public:
Class(std::vector<Var> arg) : v{arg} {}
std::vector<Var> v;
};
無論是否定義了BROKEN
,Clang ++(7.0.1)都可以無錯誤地編譯它,但是如果定義了BROKEN
則g ++(8.2.1)會引發錯誤:
main.cpp:9:20: error: cannot convert ‘std::vector<Var>’ to ‘int’ in initialization
Var(T x) : value(x) {}
^
據我所知,這里使用的統一初始化應該在兩種情況下都選擇std::vector(std::vector&&)
構造函數; 然而,顯然, g++
會將{arg}
視為初始化列表並嘗試初始化v
的第一個元素,並將Var
應用於向量,這將無效。
如果沒有定義BROKEN
,那么g ++顯然足夠聰明,可以意識到initializer_list重載不起作用。
這是正確的行為,還是標准允許的?
以下是解決該問題的兩種方法:
class Var {
public:
#ifdef BROKEN
template <typename T>
Var(T x, typename std::enable_if<std::is_convertible<T, int>::value>::type* = nullptr) : value(x) {}
#else
Var(int x) : value(x) {}
#endif
int value;
};
現場演示 。
要么:
class Class {
public:
Class(std::vector<Var> arg) : v(arg) {}
std::vector<Var> v;
};
現場演示 。
現在顯然在gcc嘗試使用模板參數作為初始化列表。 使用大括號並定義初始化列表時,初始化列表的優先級高於復制構造函數。
因此,添加適當的enable_if
可以解決問題,因為它可以防止創建構造函數的初始化列表版本。 在C ++中,20個概念將以更好的方式解決這個問題。
而當使用括號而不是大括號來初始化v
初始化列表時不可取。
我不確定誰是對的(IMO鏗鏘,但這只是一種直覺)。 也許更了解標准的人可以說出來。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.