Как написать Any с uniform initialization
От: Molchalnik  
Дата: 28.11.19 03:04
Оценка: :)
В общем так. написал аналог std::any, свой, собственный (когда ещё std::any не было на моей платформе). Назовём его Any. Проблема в том, чтобы можно было инициализировать std::vector<Any> через фигурные скобочки. Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию. Как задавить? Пока я додумался только до friendly шаблонного класса со специализациями, который вызывает нужную функцию инициализации.

upd. набрал пример на колиру второпях — исправил.
Отредактировано 28.11.2019 7:18 Molchalnik . Предыдущая версия . Еще …
Отредактировано 28.11.2019 7:16 Molchalnik . Предыдущая версия .
Re: Как написать Any с uniform initialization
От: night beast СССР  
Дата: 28.11.19 07:04
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию.


это, естественно, не так.
Re[2]: Как написать Any с uniform initialization
От: Molchalnik  
Дата: 28.11.19 07:14
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, Molchalnik, Вы писали:


M>>Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию.


NB>это, естественно, не так.


приведённый на колиру пример посмотри. везде печатает "template"

мне всегда казалось, что если перегрузка функции задана в одной единице транлсяции с шаблонной, то при совпадении типов сработает перегрузка. Но в приведённом примере всё наоборот. Если бы я понимал, почему перегрузка не давит шаблонный вариант, я бы и не задавал вопрос.
Отредактировано 28.11.2019 7:15 Molchalnik . Предыдущая версия .
Re[3]: Как написать Any с uniform initialization
От: night beast СССР  
Дата: 28.11.19 07:17
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>>>Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию.


NB>>это, естественно, не так.


M>приведённый на колиру пример посмотри. везде печатает "template"


очевидно, в примере ошибка
подсказка, выводи типы параметров.
Re[4]: Как написать Any с uniform initialization
От: Molchalnik  
Дата: 28.11.19 07:19
Оценка:
Здравствуйте, night beast, Вы писали:

M>>приведённый на колиру пример посмотри. везде печатает "template"


NB>очевидно, в примере ошибка

NB>подсказка, выводи типы параметров.

я поправил ошибку, с темплейтом в конструкторе по умолчанию и заданием функции вместо созданием Any с конструктором по умолчанию
проблема осталась. хотя подключился move-конструктор
Отредактировано 28.11.2019 7:20 Molchalnik . Предыдущая версия .
Re[5]: Как написать Any с uniform initialization
От: night beast СССР  
Дата: 28.11.19 07:28
Оценка:
Здравствуйте, Molchalnik, Вы писали:

NB>>очевидно, в примере ошибка


M>я поправил ошибку, с темплейтом в конструкторе по умолчанию и заданием функции вместо созданием Any с конструктором по умолчанию

M>проблема осталась. хотя подключился move-конструктор

NB>>подсказка, выводи типы параметров.


чтобы поключился не мув, нужен и не конст копи к-тор.

PS: да, с дефаултовой версией копи к-тора ошибся
Отредактировано 28.11.2019 7:41 night beast . Предыдущая версия .
Re: Как написать Any с uniform initialization
От: Igore Россия  
Дата: 28.11.19 07:56
Оценка: 1 (1) +1
Здравствуйте, Molchalnik, Вы писали:

M>В общем так. написал аналог std::any, свой, собственный (когда ещё std::any не было на моей платформе). Назовём его Any. Проблема в том, чтобы можно было инициализировать std::vector<Any> через фигурные скобочки. Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию. Как задавить? Пока я додумался только до friendly шаблонного класса со специализациями, который вызывает нужную функцию инициализации.


M>upd. набрал пример на колиру второпях — исправил.

Добавь
Any( Any& )  {printf("\ncopy2");}

И раз в заголовке uniform, то
Any x1{ x0 };

правильно работает
Отредактировано 28.11.2019 7:57 Igore . Предыдущая версия .
Re: Как написать Any с uniform initialization
От: B0FEE664  
Дата: 28.11.19 09:28
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию. Как задавить?


Почему:
template <typename Tn> Any( Tn && ) {printf("\ntemplate");}

вместо
template <typename Tn> Any( Tn ) {printf("\ntemplate");}

?
И каждый день — без права на ошибку...
Re: Как написать Any с uniform initialization
От: sergii.p  
Дата: 28.11.19 09:38
Оценка:
Здравствуйте, Molchalnik, Вы писали:

эта стандартная проблема имеет стандартное решение

#include <iostream>
using namespace std;
struct Any {
  Any( ) {cout << "\ndefault";}
  template <typename Tn, typename = std::enable_if_t<!std::is_convertible<Tn, Any>::value>> Any( Tn && ) {cout << "\ntemplate";}
  Any( const Any & )  {cout << "\ncopy";}    
  Any( Any&& )  {cout << "\nmove";}
};

int main() {

  Any x0;
  Any x1( x0 );
  Any x2( std::move(x0) );
  Any x3( 3 );

  return 0;
}


проблема не в том, что заменяется конструктор копирования. Просто для неконстантного объекта лучшим соответствием считается шаблонный конструктор. Если в примере поставить Any const x0 то всё будет также работать — конструктор вызовется
Re[2]: Как написать Any с uniform initialization
От: night beast СССР  
Дата: 28.11.19 09:42
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>эта стандартная проблема имеет стандартное решение


может не сработать на старых реализациях, т.к. неиспользуемые шаблонные параметры с дефолтным значением в старых версиях стандарта в SFINAE не участвуют.
Отредактировано 28.11.2019 9:44 night beast . Предыдущая версия .
Re[2]: Как написать Any с uniform initialization
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 28.11.19 09:58
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Molchalnik, Вы писали:


M>>Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию. Как задавить?


BFE>Почему:

BFE>
BFE>template <typename Tn> Any( Tn && ) {printf("\ntemplate");}
BFE>

BFE>вместо
BFE>
BFE>template <typename Tn> Any( Tn ) {printf("\ntemplate");}
BFE>

BFE>?
perfect forwarding?
Sic luceat lux!
Отредактировано 28.11.2019 11:49 Kernan . Предыдущая версия .
Re[3]: Как написать Any с uniform initialization
От: sergii.p  
Дата: 28.11.19 10:00
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, sergii.p, Вы писали:


SP>>эта стандартная проблема имеет стандартное решение


NB>может не сработать на старых реализациях, т.к. неиспользуемые шаблонные параметры с дефолтным значением в старых версиях стандарта в SFINAE не участвуют.


если не сработает, тогда и надо думать Как минимум это решение для данной проблемы пропагандирует Джосаттис.
Re[3]: Как написать Any с uniform initialization
От: B0FEE664  
Дата: 28.11.19 10:35
Оценка:
Здравствуйте, Kernan, Вы писали:

K>prefect forwarding?

точно. забыл об этом.
И каждый день — без права на ошибку...
Re: Как написать Any с uniform initialization
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 28.11.19 11:31
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>В общем так. написал аналог std::any, свой, собственный (когда ещё std::any не было на моей платформе). Назовём его Any. Проблема в том, чтобы можно было инициализировать std::vector<Any> через фигурные скобочки. Но это нифига не выходит, потому что нужно вводть шаблонный конструктор, а он заменяет собой конструктор копирования по умолчанию. Как задавить? Пока я додумался только до friendly шаблонного класса со специализациями, который вызывает нужную функцию инициализации.

Я совсем не понял проблему и что тебе не нравится. Попробуй убрать вот так:
struct Any {
  Any( ) {printf("\ndefault");}
  template <typename Tn> Any( Tn && ) {printf("\ntemplate");}
};


конструкция
template <typename Tn> Any( Tn && ) {printf("\ntemplate");}

Это prefect forwarding, а не шаблонный конструктор, тебе не надо в этом случае переопределять копирование и перемещение.
Sic luceat lux!
Re[2]: Как написать Any с uniform initialization
От: night beast СССР  
Дата: 28.11.19 12:11
Оценка:
Здравствуйте, Kernan, Вы писали:

K>конструкция

K>
K>template <typename Tn> Any( Tn && ) {printf("\ntemplate");}
K>

K>Это prefect forwarding, а не шаблонный конструктор, тебе не надо в этом случае переопределять копирование и перемещение.

выяснилось что по умолчанию дефаултовый конструктор для не-конст ссылки не создается, и эта версия имеет большее соответствие, чем сгенерированный автоматически копи к-тор.
Re[2]: Как написать Any с uniform initialization
От: Molchalnik  
Дата: 28.11.19 20:56
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, Molchalnik, Вы писали:




K>конструкция

K>
K>template <typename Tn> Any( Tn && ) {printf("\ntemplate");}
K>

K>Это prefect forwarding, а не шаблонный конструктор, тебе не надо в этом случае переопределять копирование и перемещение.

Надо в связи с особенностями реализации

конструктор Any{int} и Any{Any &&} работает совершенно по-разному в моём коде. разве что шаблонный класс-хелпер-инициализатор со специализациями сделать вместо конструктора — и передавать из универсального шаблонного конструктора в него — но это сложно и поэтому убого выглядит
Re[2]: Как написать Any с uniform initialization
От: Molchalnik  
Дата: 28.11.19 20:57
Оценка:
Здравствуйте, Igore, Вы писали:

I>Добавь

I>
I>Any( Any& )  {printf("\ncopy2");}
I>


спасибо. поставил плюсик. а почему не происходит best fit на const Any& ? В каком разделе стандарта можно прочитать?
Re[3]: Как написать Any с uniform initialization
От: rg45 СССР  
Дата: 28.11.19 22:08
Оценка: +1
Здравствуйте, Molchalnik, Вы писали:

I>>Добавь

I>>
I>>Any( Any& )  {printf("\ncopy2");}
I>>


M>спасибо. поставил плюсик. а почему не происходит best fit на const Any& ? В каком разделе стандарта можно прочитать?


Это особый вид ссылок, известный под кодовым названием Forwarding references. Когда ты используешь для конструирования lvalue выражение, параметр с типом "Тn &&" отображается на тип "Any& &&" (да-да, ссылка на ссылку). После этого происходит так называемый коллапсинг избыточных ссылок, по описанному в стандарте правилу, и получается конечный тип формального параметра "Any&". И этот тип лучше подходит для неконстантного объекта, чем "const Any&".
--
Отредактировано 28.11.2019 22:20 rg45 . Предыдущая версия . Еще …
Отредактировано 28.11.2019 22:20 rg45 . Предыдущая версия .
Отредактировано 28.11.2019 22:18 rg45 . Предыдущая версия .
Re[3]: Как написать Any с uniform initialization
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 29.11.19 09:11
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Надо в связи с особенностями реализации

Ты не понимаешь что тебе надо и зачем.

M>конструктор Any{int} и Any{Any &&} работает совершенно по-разному в моём коде. разве что шаблонный класс-хелпер-инициализатор со специализациями сделать вместо конструктора — и передавать из универсального шаблонного конструктора в него — но это сложно и поэтому убого выглядит

Ну так перегрузи его
  template<class T>
    Any(std::initializer_list<T>&&) { std::cout<<"foo"<<std::endl;  }

и в мейн
  Any a{10};

делай везде префект порвардинг и не будет лишних копирований.
Sic luceat lux!
Re[4]: Как написать Any с uniform initialization
От: rg45 СССР  
Дата: 29.11.19 10:14
Оценка: +2
Здравствуйте, Kernan, Вы писали:

M>>конструктор Any{int} и Any{Any &&} работает совершенно по-разному в моём коде. разве что шаблонный класс-хелпер-инициализатор со специализациями сделать вместо конструктора — и передавать из универсального шаблонного конструктора в него — но это сложно и поэтому убого выглядит

K>Ну так перегрузи его
K>
K>  template<class T>
K>    Any(std::initializer_list<T>&&) { std::cout<<"foo"<<std::endl;  }
K>

K>и в мейн
K>
K>  Any a{10};
K>

K>делай везде префект порвардинг и не будет лишних копирований.

Настало время вредных советов? Бездумное применение perfect forwarding — это современный изощренный способ стрельбы по собственным конечностям, а тем более, если ВЕЗДЕ.

И кстати, в твоем примере это никакой не perfect forwarding, а просто rvalue ссылка на объект initializer_list. Который, даже сам являясь времменным объектом, предоставляет доступ к своим элементам исключительно по константным lvalue ссылкам. Поэтому перемешение содержимого initializer_list невозможно в принципе. Пруф здесь.
--
Отредактировано 29.11.2019 11:10 rg45 . Предыдущая версия . Еще …
Отредактировано 29.11.2019 11:10 rg45 . Предыдущая версия .
Отредактировано 29.11.2019 10:23 rg45 . Предыдущая версия .
Отредактировано 29.11.2019 10:20 rg45 . Предыдущая версия .
Отредактировано 29.11.2019 10:20 rg45 . Предыдущая версия .
Отредактировано 29.11.2019 10:19 rg45 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.