1

В приведенном ниже коде вызов функции-члена F экземпляра b с аргументом {1,2} компилируется и звонит B::F(std::initializer_list<int>). Но если удалить один элемент из рамно-Init-лист и использовать только {1}, я получаю сообщение об ошибкеПочему тип скопированного init-списка с одним элементом переключается на тип самого элемента?

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

Из-за «равномерной инициализации» :-) –

ответ

1

Хорошо, я думаю, что понял. Когда компилятор видит b.F({1}), он пытается выяснить, какая перегрузка F для вызова. Он видит, что есть перегрузка, которая принимает A<int>, поэтому через copy-list-initialization она пытается увидеть, может ли она построить A<int> с использованием A<int>{1}. Тип литерала 1 - int. Таким образом, TA выводится как 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 < Int> :: типа является отказ замены.

Смежные вопросы