range-declaration при range-based for
От: Videoman Россия https://hts.tv/
Дата: 28.11.23 20:31
Оценка:
Следующий код работал в VS2017 и перестал работать в последних VS2022, gcc и clang:
#include <array>
#include <string>
#include <optional>
#include <iostream>
#include <memory>

namespace com
{
    template<typename interface_t>
    class ptr
    {
    public:
        ptr(interface_t* ptr = nullptr) noexcept { m_ptr = ptr; }

        operator interface_t*() const noexcept { return m_ptr; }

    private:
        interface_t* m_ptr;
    };
}

class pin
{
public:
    pin(int* v) {};
};


int main()
{
    std::array<com::ptr<int>, 10> arr_of_ptr;

    for (pin p : arr_of_ptr) // error:  no viable conversion from 'value_type'
    { 

    }
    
    pin p1(arr_of_ptr[0]);  // ок:      case 1
    pin p2 = arr_of_ptr[0]; // error:   case 2

}
У меня догадка такая, что раньше VS генерировал case1, а теперь по стандарту должен case2, т.е. разные виды инициализации. Вопросы:
1. Прав ли я и теперь по стандарту возможен лишь второй вариант?
2. Можно ли как-то в таком range-for заставить вызваться пользовательское преобразование?
Re: range-declaration при range-based for
От: reversecode google
Дата: 28.11.23 21:04
Оценка:
можно (int*)
pin p2 = (int*)arr_of_ptr[0]; // error:   case 2


но в остальном оно имеет несколько другую природу как мне кажется
Отредактировано 28.11.2023 21:06 reversecode . Предыдущая версия .
Re[2]: range-declaration при range-based for
От: Videoman Россия https://hts.tv/
Дата: 28.11.23 21:25
Оценка:
Вопрос прочитай внимательнее. Он не в том, как заставить это код работать, а скорее почему это раньше работало, в VS2017 ?

R>можно (int*)


Как я это в цикле for (pin p : arr_of_ptr) укажу ?
Re[3]: range-declaration при range-based for
От: reversecode google
Дата: 28.11.23 21:29
Оценка:
у стандарта нет никаких VS2017
есть С++11 есть С++17 итд
в обеих 11 и 17 и в gcc и в clang это не работает насколько я вижу

поэтому вопрос к студии а не к стандарту
Re: range-declaration при range-based for
От: rg45 СССР  
Дата: 28.11.23 23:33
Оценка: 4 (1)
Здравствуйте, Videoman, Вы писали:

V>Следующий код работал в VS2017 и перестал работать в последних VS2022, gcc и clang:
V>#include <array>
V>#include <string>
V>#include <optional>
V>#include <iostream>
V>#include <memory>

V>namespace com
V>{
V>    template<typename interface_t>
V>    class ptr
V>    {
V>    public:
V>        ptr(interface_t* ptr = nullptr) noexcept { m_ptr = ptr; }

V>        operator interface_t*() const noexcept { return m_ptr; }

V>    private:
V>        interface_t* m_ptr;
V>    };
V>}

V>class pin
V>{
V>public:
V>    pin(int* v) {};
V>};


V>int main()
V>{
V>    std::array<com::ptr<int>, 10> arr_of_ptr;

V>    for (pin p : arr_of_ptr) // error:  no viable conversion from 'value_type'
V>    { 

V>    }
    
V>    pin p1(arr_of_ptr[0]);  // ок:      case 1
V>    pin p2 = arr_of_ptr[0]; // error:   case 2

V>}
V>
У меня догадка такая, что раньше VS генерировал case1, а теперь по стандарту должен case2, т.е. разные виды инициализации. Вопросы:

V>1. Прав ли я и теперь по стандарту возможен лишь второй вариант?
V>2. Можно ли как-то в таком range-for заставить вызваться пользовательское преобразование?

Так а тут же двойной user-defined conversion получается. По идее, это и раньше не должно было работать без дополнительного явного приведения: https://en.cppreference.com/w/cpp/language/implicit_conversion
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: range-declaration при range-based for
От: Videoman Россия https://hts.tv/
Дата: 29.11.23 07:13
Оценка:
Здравствуйте, rg45, Вы писали:

R>Так а тут же двойной user-defined conversion получается. По идее, это и раньше не должно было работать без дополнительного явного приведения: https://en.cppreference.com/w/cpp/language/implicit_conversion


— точно! Что-то видимо вчера вечером мой калькулятор user-defined conversion сломался. Это всё компилятор старой студии, слишком жадный был и привычки неправильные формирует. Спасибо!
Re[4]: range-declaration при range-based for
От: Videoman Россия https://hts.tv/
Дата: 29.11.23 07:15
Оценка:
Здравствуйте, reversecode, Вы писали:

R>поэтому вопрос к студии а не к стандарту


Да я в курсе, что допускается одно user-defined преобразование и бесконечное количество стандартных. Просто старый код отваливается, т.к. писался еще под VS2017.
Re[5]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 13:39
Оценка:
кто мешает подключить clang и узнать много интересного ?

я как минимум сразу двумя собираю и cl и clang-cl

особенно задалбывает msvc шный имплиситный конструктор на любую структуру который по умолчанию берет первый елемент структуры

ни gcc ни clang такого не понимает
Re[6]: range-declaration при range-based for
От: rg45 СССР  
Дата: 29.11.23 14:26
Оценка:
Здравствуйте, reversecode, Вы писали:

R>особенно задалбывает msvc шный имплиситный конструктор на любую структуру который по умолчанию берет первый елемент структуры


Можно небольшой пример, чтоб понимать, о чем речь?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[7]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 14:35
Оценка:
подрукой нет
по памяти на глаз

struct A
{
   int a;
   std::string b;
   float c;
   //итд

//  A(int aa):a(aa){} // не обявив явно не работает в gcc clang
};

int main()
{
    auto p = std::make_shared<A>(3);
}

и не только на make_shared
там на много другого тоже самое
на std::map итд
Re[8]: range-declaration при range-based for
От: rg45 СССР  
Дата: 29.11.23 14:43
Оценка:
Здравствуйте, reversecode, Вы писали:

R>

R>struct A
R>{
R>   int a;
R>   std::string b;
R>   float c;
R>   //итд

R>//  A(int aa):a(aa){} // не обявив явно не работает в gcc clang
R>};

R>int main()
R>{
R>    auto p = std::make_shared<A>(3);
R>}
R>

R>и не только на make_shared
R>там на много другого тоже самое
R>на std::map итд

Так в std::make_shared коструктор используется как раз эксплиситный. И этот пример с успехом компилит не только msvc:

http://coliru.stacked-crooked.com/a/3b5f64924da2429a

Имплиситный конструктор был бы, если бы компилилось что-то типа такого:

void foo(A);

int main()
{
    foo(3);
}


Но такое не компилится, к счастью, нигде, в т.ч. и в msvc.

И вот так можно:

A a_explicit{42}; // OK


А вот так нельзя:

A a_implicit = 42; // error: conversion from 'int' to non-scalar type 'A' requested


А вот если раскомментируешь user-defined конструктор в классе А, то станут возможны оба варианта. Хоть ты и называешь этот конструктор явным, на самом деле, это неявный конструктор — user-defined implicit constructor.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.11.2023 15:16 rg45 . Предыдущая версия . Еще …
Отредактировано 29.11.2023 14:58 rg45 . Предыдущая версия .
Re[9]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 14:58
Оценка:
забыл
virtual ~A(){}
Re[10]: range-declaration при range-based for
От: rg45 СССР  
Дата: 29.11.23 15:09
Оценка:
Здравствуйте, reversecode, Вы писали:

R>забыл

R>
R>virtual ~A(){}
R>



Ну это понятно, что виртуальный деструктор блокирует агрегатную инициализацию. Так и в MSVC то же самое. Я не поленился только что попробовал на MSVC 2022, причем, с разными тулсетами и стандартами языка.

Есть пример, который в gcc и clang работает правильно, а в msvc — неправильно?
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.11.2023 15:10 rg45 . Предыдущая версия .
Re[11]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 15:27
Оценка:
в msvс работает без явного конструктора
в gcc clang нужно конструктор обьявлять явно
где правильно или не правильно я хз, скорее всего не правильно было в msvc
пофиксили ли это в 2022 студии я не проверял
в 2019 это задабывало

если пример все же не срабатывает
значит прийдется лезть в коммиты и искать уточнения по примеру

касательно агрегатной инициализации она тоже нигде не работает
во всех трех компилерах
там вроде для std::list ее как то поправили
но для std::map и еще разного другого не будет работать
где то был пост какого то умного чела на эту тему даже
Re[12]: range-declaration при range-based for
От: rg45 СССР  
Дата: 29.11.23 15:48
Оценка:
Здравствуйте, reversecode, Вы писали:

R>в msvс работает без явного конструктора


Я тебе писал уже здесь
Автор: rg45
Дата: 29.11 17:43
: ты путаешься в понятиях "явный" (explicit) и "определенный пользователем" (user-defined). Тот конструктор
Автор: reversecode
Дата: 29.11 17:35
, который ты называешь явным, на самом деле является НЕявным — это user-defined implicit constructor.

R>в gcc clang нужно конструктор обьявлять явно


Да, но только примера ты так и не привел, как я просил — такого, который работает правильно в gcc и неправильно в msvc. Ну ладно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.11.2023 15:55 rg45 . Предыдущая версия . Еще …
Отредактировано 29.11.2023 15:54 rg45 . Предыдущая версия .
Отредактировано 29.11.2023 15:51 rg45 . Предыдущая версия .
Отредактировано 29.11.2023 15:50 rg45 . Предыдущая версия .
Re[13]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 16:41
Оценка: 1 (1)
ладно пусть будет user-defined

вообщем грохул все такие конструкторы
пересобрал с С++20
и оказывается уже везде работает emplace_back для агрегатной инициализации

в С++17 это не работало

struct AA
{
   unsigned short a;
   unsigned int b;
};

int main()
{
    std::vector<AA> aa;
    std::list<AA> cc;
    
    aa.emplace_back(1,2);
    cc.emplace_back(1,2);
}


но это агрегатная

кейс где msvc молча жует первый аргумент конструктором без объявления конструктора
пока не нашел, много воды утекло за два года в коммитах
Re[14]: range-declaration при range-based for
От: rg45 СССР  
Дата: 29.11.23 16:51
Оценка:
Здравствуйте, reversecode, Вы писали:

R>в С++17 это не работало


А сейчас у тебя какая студия? Там, начиная с 2017-й (если память меня не подводит), есть возможность переключения тулсетов. Понижение версии тулсета, по идее, должно быть эквивалентно пересадке на более старые версии студии. Ну, понятно, есть опция переключения стандарта языка и есть еще одна, не очень заметная на первый взгляд опция — Conformance Mode. Это типа степень соответсвия требованиям стандарта языка и от этой опции зависит многое. Так что, можно поиграться со всем этим набором, при желании.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.11.2023 17:16 rg45 . Предыдущая версия .
Re[15]: range-declaration при range-based for
От: reversecode google
Дата: 29.11.23 17:25
Оценка: 9 (2)
таксь кажеться я разобрался
на этих проектах С++20 я включил уже давненько
а компилеры только начали подтягивать постепенно все новшества

соответсвенно вот этот кейс
#include<string>
#include<map>
#include<vector>
struct AA
{
   std::string a;
   unsigned int b;
   std::string c;
   unsigned char d;
   std::vector<unsigned int> e;
   bool f;
   bool h;
};

int main()
{
    std::map<unsigned short, AA> aa;
    aa.insert(std::make_pair(1,"d"));
}


на clang 15 C++20 это не компилится
но уже на clang 16 и выше с C++20 это комилиться
я clang постоянно как только очередной релиз обновляю, но эти нюансы как что компилилось отваливалось уже не проверяю, компилиться и ладно

на msvc это всегда компилилось с момента заявления поддержки C++20

соответсвенно я сделал выводы что msvc глючит
так как clang и помоему на gcc я это тоже проверял, не компилилось

а теперь получается что это ок
и видимо по правилу агрегатной инициализации вполне нормально брать первый елемент структуры как первый аргумент

соотвественно и примеры выше
я тоже помню что я их с С++20 начинал делать
и там тоже не компилилось без user defined ctor которые повторяли аргументами тот же порядок елементов
тоесть я делал двойную работу

ну значит фух
если все это пофиксили
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.