簡體   English   中英

C ++ std :: vector initializer_list重載歧義(g ++ / clang ++)

[英]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重載不起作用。

這是正確的行為,還是標准允許的?

BROKEN定義了gcc
BROKEN沒有定義gcc
BROKEN定義了clang

以下是解決該問題的兩種方法:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM