請幫助我理解為什么不能將std::initializer_list 文字推斷為模板引數?AFAIK,語言中還沒有初始化串列文字的概念,但是為什么/如何作業?
auto il = { 1, 2, 3, 4, 5 };
這是我的代碼:
import <iostream>;
import <string>;
import <vector>;
template <typename T>
constexpr auto type_name() {
std::string_view name, prefix, suffix;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
prefix = "auto type_name() [T = ";
suffix = "]";
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
prefix = "constexpr auto type_name() [with T = ";
suffix = "]";
#elif defined(_MSC_VER)
name = __FUNCSIG__;
prefix = "auto __cdecl type_name<";
suffix = ">(void)";
#endif
name.remove_prefix(prefix.size());
name.remove_suffix(suffix.size());
return name;
}
template< typename T >
int SAI_BF_helper(T&&) { return 0; }
int SAI_BF_helper(int i) { return i; }
// function that take any number parameters of any type and then return sum of all ints using binary left folding expressions
template< typename ... Types >
?int SumAllInts_BinaryLeftFold(Types ... args)
{
return (0 ... SAI_BF_helper(args));
}
template< typename T >
void PrintTypeName(T&& t)
{
std::cout << type_name< decltype( std::forward< T >(t) )> () << std::endl;
}
// if this overload is removed then 'PrintTypeName({1,2,3});' code will not compile
template< typename T >
void PrintTypeName( std::initializer_list< T >&& t)
{
std::cout << type_name< decltype(std::forward< std::initializer_list< T > >(t))>() << std::endl;
}
int main()
{
std::vector< int > numbers{ 1, 2, 3 };
auto il = { 1, 2, 3, 4, 5 };
PrintTypeName(numbers); // output: class std::vector<int,class std::allocator<int> >&
PrintTypeName(il); // output: class std::initializer_list<int>&
PrintTypeName({1,2,3}); // output: class std::initializer_list<int>&&
std::cout << SumAllInts_BinaryLeftFold() << std::endl; // 0
std::cout << SumAllInts_BinaryLeftFold("", 0, 1, 2.2, 'a', "char*", 10, std::string("str"), numbers, il) << std::endl; // 11
//std::cout << SumAllInts_BinaryLeftFold( 1, {1, 2}) << std::endl; // MSVC error message: 'initializer list': is not a valid template argument for 'Types'
}
uj5u.com熱心網友回復:
簡短的回答:初始化串列(語言機制,而不是型別)很神奇。不完全是。
C 標準對初始化串列語法有明確的措辭,以在某些情況下生成std::initializer_list物件,例如構造-auto引數,但初始化串列運算式本身并不總是一個std::initializer_list; 這取決于具體情況。
之所以需要這種區別,是因為可以使用相同的語法來代替引數等情況的隱式構造。例如,考慮以下代碼:
auto do_something(Person) -> void;
...
do_something({}); // Calls Person() -- not Person(std::initializer_list<U>)
在此,{}不意味著是一個std::initializer_list物件;它是 . 的隱式默認構造Person。
因為存在這些情況,所以推斷大括號括起來的初始化器串列的確切型別并不是那么簡單。例如:
template <typename T>
auto do_something(T) -> void;
do_something({1}) -> void;
在上述情況下,應該T是什么?是do_something<std::initializer_list<int>>嗎?do_something<int>與int{1}?如果是這樣{1, 2U}呢?它可能會變得復雜。
uj5u.com熱心網友回復:
沒有“std::initializer_list字面意思”這樣的東西。 {1, 2, 3}是一個花括號初始化串列;一種沒有型別的句法構造,可用于初始化許多型別。有一些特定的情況(見下文)std::initializer_list會從一個花括號初始化串列隱式創建,但它們不是一回事。
從cppreference:
在
std::initializer_list以下情況下會自動構造物件:
- 一個花括號初始化串列用于串列初始化一個物件,其中相應的建構式接受一個
std::initializer_list引數- 花括號初始化串列用作賦值的右運算元或函式呼叫引數,并且相應的賦值運算子/函式接受
std::initializer_list引數- 一個花括號初始化串列系結到
auto,包括在一個范圍內的 for 回圈中
auto il = {1, 2, 3, 4, 5};
std::initializer_list這是從花括號初始化串列隱式創建的情況之一。一個花括號初始化串列被系結到auto.
template <typename T>
void PrintTypeName(std::initializer_list<T>&& t)
{
...
}
PrintTypeName({1,2,3});
這是另一種特定情況,其中花括號初始化串列自動轉換為std::initializer_list. 一個花括號初始化串列被用作函式呼叫引數,并且相應的函式接受一個std::initializer_list引數。
template<typename T>
void PrintTypeName(T&& t)
{
...
}
PrintTypeName({1,2,3});
這不是括號初始化串列會自動轉換為std::initializer_list. 這PrintTypeName并不專門接受一個std::initializer_list.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/515149.html
標籤:C 模板可变参数模板
上一篇:使用函式回傳型別的類模板引數推導
