почему мне нужно использовать std :: decay в следующем случае? - PullRequest
0 голосов
/ 16 сентября 2018

Я новичок в C ++ и создал тестовую программу, чтобы узнать больше о decltype, std::decay, std::is_same_v (черты), а также typeid.

У меня следующий простой класс,в котором я хотел получить тип параметра шаблона Type в конструкторе класса Base, используя decltype.

подобно decltype(content of std::vector<Type>::iterator::begin).Каким-то образом это не сработало.

#include <iostream>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <typeindex>

template<typename Type> class Base
{
    std::vector<Type> vec;
public :
    Base(std::initializer_list<decltype(*vec.begin())> liVec): vec(liVec) {}
    // here                    ^^^^^^^^^^^^^^^^^^^^^^^^ . isn't enough?? 
};

int main()
{
    //Base<int> obj{ 1, 2, 3, 4, 5 };     // does not works: error !

    // to see the type, I wrote the following code
    std::vector<int> vec;
    std::cout << typeid(decltype(*vec.begin())).name() << std::endl; // prints i means int type(I know not reliable though)
    // and
    std::cout << std::boolalpha << std::is_same_v<int, decltype(*vec.begin())> << std::endl; // prints false 

    return 0;
}

Ошибка в строке Base<int> obj{ 1, 2, 3, 4, 5 }; была (в GCC 6.1, C ++ 14)

include\c++\initializer_list||In instantiation of 'class std::initializer_list<int&>':|
include\c++\initializer_list|54|error: forming pointer to reference type 'int&'|
include\c++\initializer_list|55|error: forming pointer to reference type 'int&'|
main.cpp|17|error: no matching function for call to 'Base<int>::Base(<brace-enclosed initializer list>)'|
candidate: 'Base<Type>::Base(std::initializer_list<decltype (*((Base<Type>*)(void)0)->Base<Type>::vec.begin())>) [with Type = int; decltype (*((Base<Type>*)(void)0)->Base<Type>::vec.begin()) = int&]'|
main.cpp|11|note:   candidate expects 1 argument, 5 provided|
main.cpp|7|note: candidate: 'Base<int>::Base(const Base<int>&)'|
main.cpp|7|note:   candidate expects 1 argument, 5 provided|
main.cpp|7|note: candidate: 'Base<int>::Base(Base<int>&&)'|
main.cpp|7|note:   candidate expects 1 argument, 5 provided|

Как я видел компиляторсказал мне что-то о int&, я просто попробовал это со следующим. (т.е. std::decay_t), и это сработало.

template<typename Type> class Base
{
    std::vector<Type> vec;
public :
    Base(std::initializer_list<std::decay_t<decltype(*vec.begin())>> liVec): vec(liVec) {}
                               ^^^^^^^^^^^^^^^^^^^^^^^^ why I need this here?
};

int main()
{
    Base<int> obj{ 1, 2, 3, 4, 5 };     // works now

    std::vector<int> vec;
    std::cout << typeid(decltype(*vec.begin())).name() << std::endl; // prints i means int type(not reliable though)
    // and
    std::cout << std::boolalpha << std::is_same_v<int, std::decay_t<decltype(*vec.begin())>> << std::endl; // true now: WHY?

    return 0;
}

Но я не знаю значения ошибки и почему она сработала.Может ли кто-нибудь объяснить мне, что именно произошло?

1 Ответ

0 голосов
/ 16 сентября 2018

Первая строка ваших сообщений об ошибках гласит (между прочим):

instantiation of 'class std::initializer_list<int&>'

Итак, он пытается создать initializer_list с ссылочным типом , что недопустимо.

Глядя на код вашего шаблона:

 std::initializer_list<decltype(*vec.begin())>

Теперь vec.begin() возвращает итератор и разыменование итератора дает ссылку , так что вы можете делать такие вещи, как:

*iter = whatever;

Таким образом, вам нужно удалить ссылку часть типа. std :: decay_t делает это.

...