簡體   English   中英

消除std :: vector的列表初始化消除歧義<std::string>

[英]Disambiguating list initialization for std::vector<std::string>

我的代碼中有一個帶有類型簽名的重載函數:

void foo(std::string);
void foo(std::vector<std::string>);

我希望foo的用戶能夠使用字符串或字符串列表來調用它

//Use case 1
foo("str");

//Use case 2
foo({"str1","str2","str3"});
foo({"str1","str2","str3","str4"});

問題是當調用者將兩個字符串傳入foo的初始化列表時。

//Problem!
foo({"str1","str2"});

這種對foo的調用是不明確的,因為它匹配兩種類型的簽名。 這是因為顯然{"str1","str2"}std::string的有效構造函數

所以我的問題是我在foo的聲明或實現中可以做些什么,這樣我就可以維護上面描述的API而不會遇到這種模糊的構造函數。

我不想定義自己的字符串類,但我可以定義其他東西而不是vector<string> ,只要它可以使用初始化字符串列表進行初始化。

出於好奇,為什么字符串構造函數接受{"str1","str2"}

{"str1","str2"}匹配接受兩個迭代器的std::string構造函數。 構造函數6 在這里 它會嘗試從“str1”的開頭迭代到“str2”的開頭,這是未定義的行為。

您可以通過引入std::initializer_list<const char*>的重載來解決這種歧義,該重載轉發到std::vector<std::string>重載。

void foo(std::string);
void foo(std::vector<std::string>);

void foo(std::initializer_list<const char*> p_list)
{
    foo(std::vector<std::string>(p_list.begin(), p_list.end()));
}

您可以使用可變參數模板稍微更改您的API,這可以防止您遇到的歧義。

template <typename... Ts>
auto foo(Ts...) 
    -> std::enable_if_t<all_are_convertible_to<std::string, Ts...>, void> 
{ 
    /* ... */ 
}

用法:

foo("aaaa");
foo("aaaa", "bbb", "cc", "d");

在C ++ 17中, all_are_convertible_to可以用fold表達式 (或std::conjunction )實現:

template <typename T, typename... Ts>
inline constexpr bool are_all_convertible = 
    (std::is_convertible_v<Ts, T> && ...);

在C ++ 11中,您可以實現某種遞歸類型特征,如下所示:

template <typename, typename...>
struct are_all_convertible_to_helper;

template <typename T, typename X, typename... Xs>
struct are_all_convertible_to_helper<T, X, Xs...>
    : std::integral_constant<bool,
         std::is_convertible<X, T>::value && are_all_convertible_to_helper<T, Xs...>::value
    >
{
};

template <typename T>
struct are_all_convertible_to_helper<T> : std::true_type
{
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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