Почему тип braced-init-list с одним элементом переключается на тип самого элемента?
В приведенном ниже коде вызов функции-члена F экземпляра b с аргументом {1,2} компилируется и вызывает B::F(std::initializer_list<int>)
, Но если я удаляю один элемент из списка braced-init-list и использую только {1}, я получаю ошибку
9 : error: no matching function for call to 'begin(int)'
using type = decltype(std::begin(std::declval<T>()));
Я не понимаю, почему компилятор ищет begin(int)
, и не begin(initializer_list<int>)
Я играл с этим на https://godbolt.org/g/tMyYQs, и я получаю одинаковую ошибку как на Clang, так и на G ++. Что мне не хватает?
#include <type_traits>
#include <iterator>
template< bool B, class T = void >
using enable_if_t = typename std::enable_if<B,T>::type;
template <typename T>
struct mytrait {
using type = decltype(std::begin(std::declval<T>()));
};
template <typename T>
class A {
public:
template <typename TA, typename =
enable_if_t<std::is_same<T, typename mytrait<TA>::type>::value>>
A(TA &&){}
};
class B
{
public:
void F(A<int>);
void F(std::initializer_list<int>);
};
int main()
{
B b;
b.F({1,2}); // compiles fine
#if 0
b.F({1}); // causes mytrait<int>::type to be examined,
// not mytrait<std::initializer_list<int>>::type
#endif
}
1 ответ
Хорошо, я думаю, я понял это. Когда компилятор видит b.F({1})
он пытается выяснить, какую перегрузку F вызвать. Он видит, что есть перегрузка, которая принимает A<int>
Таким образом, с помощью инициализации copy-list, он пытается увидеть, может ли он создать A<int>
с помощью A<int>{1}
, Тип буквального 1
это инт. Таким образом, ТА выводится как int. mytrait<int>
пытается определить decltype(std::begin(declval<int>()))
, нет типа std::begin для типа int, поэтому ошибки компилятора.
За b.F({1,2})
нет конструктора A<int>
он принимает два ввода, поэтому инициализация списка даже не предпринимается.
Похоже, я могу это исправить, изменив объявление шаблона mytraits на
template <typename T, typename = decltype(std::begin(std::declval<T>()))>
struct mytraits {...};
Кажется, это использует SFINAE, чтобы mytrait