LINUX.ORG.RU

Ниасилил C++ vector<unique_ptr<T>> list initialization

 


0

6

Допустим есть у нас следующее:

#include <memory>
#include <vector>
#include <iostream>
using namespace std;

class Base {
        int i;
    public:
        Base(int ai) : i(ai){}
        virtual ~Base() {}
        virtual void m() {
            cout << "Base::m() " << i << endl;
        }
};
class A : public Base {
    public:
        A() : Base(1) {}
        virtual ~A() {}
};
class B : public Base {
        char c;
    public:
        B(char ac) : Base(2), c(ac) {}
        virtual ~B() {}
        virtual void m() {
            Base::m();
            cout << "B::m() " << c << endl;
        }
};

int main(){
    vector<unique_ptr<Base>> v{
        /* ??? */
    };
    for (auto& a : v)
        a->m();
}

Что нужно написать, что бы инициализировать v значениями new Base(10), new A(), new B('x')?

make_unique<Base>(), unqiue_ptr<Base>(new ??()) не работают.

Ответ на: комментарий от anonymous

Вот поэтому C лучше, чем C++ :-) Там хотя бы очевидно то, что написано

С константностью в Си то же самое. Ты просто не понимаешь, что написано.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Иди уже почитай что-нибудь.

struct A {
	int foo = 0;
};

template <typename T>
struct TypeHuinter;

int main() {
	const A a;
	
//	TypeHuinter<decltype(a.foo)> d;
	TypeHuinter<decltype((a.foo))> d; // ОЙ! что же ето не так, с плюс плюс что ты делаешь, б-ги decltype() != decltype(()), вот так досада!

	return 0;
}

Kuzy ★★★
()
Ответ на: комментарий от tailgunner

Ты просто не понимаешь, что написано.

Написано, что компилятор в первом случае вывел int, а во втором - const int :-) Ты этого, что-ли, не понял, или чего ты не понял то? :-)

anonymous
()
Ответ на: комментарий от anonymous

Ау, чудо, тебе нужен тип lvalue а не объявления. Используй decltype(()).

Наслаждайся:

int main() {
	const A a;
	A b;
	
	// aggregate 'TypeHuinter<const int&> d' has incomplete type and cannot be defined
	TypeHuinter<decltype((a.foo))> d; 
	// aggregate 'TypeHuinter<int&> c' has incomplete type and cannot be defined
	TypeHuinter<decltype((b.foo))> c; 

	return 0;
}

Начинай уже читать, что тебе пишут.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Ау, чудо, тебе нужен тип lvalue а не объявления. Используй decltype(()).

Ты хоть понял, что ты сейчас объявил о своей полнейшей некомпетентности? :-) Лол :-)

anonymous
()
Ответ на: комментарий от anonymous

И сколько же вас таких вот цепепе-программистов... Мда... :-)

anonymous
()
Ответ на: комментарий от anonymous

Привет.

if e is an unparenthesized id-expression or a class member access (5.2.5), decltype(e) is the type of the entity named by e.

if e is an lvalue, decltype(e) is T&, where T is the type of e;

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Кузя, да ты английский не знаешь даже :-) Какой уж там цепепе тебе? :-) Сначала пишет одно, потом здоровается, потом приводит цитаты из стандарта, которые полностью противоречат тому, что изначально сам же написал :-) Редкий экземпляр :-)

anonymous
()
Ответ на: комментарий от Kuzy

Ясно :-)
Понятно :-)

Не похоже :-) Лол :-)

anonymous
()
Ответ на: комментарий от tailgunner

Ты просто не понимаешь, что написано.

Там написано, что компилятор в первом случае определил тип А::foo как int, несмотря на то, что a объявлен как const A a, а A::foo *не объявлен* как mutable :-) Во втором случае компилятор определил тип B::foo как const int, но не потому, что b объявлен как const B b, а потому, что B::foo объявлен как const int :-)

anonymous
()
Ответ на: комментарий от anonymous

Ага, та функция шаблон, параметризованная std::initializer_list<T>, которая была изначально предложена, - действительно undefined behaviour :-) Полез таки в стандарт и нашёл пункт 7.1.6.1/4

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.

tailgunner, на этот раз ты оказался прав :-) Kuzy, а ты в следующий раз приводи ссылки на правильные места в стандарте :-) И разберись с decltype((e)) :-)

anonymous
()
Ответ на: комментарий от anonymous

То, что структура и её члены - суть разные объекты :-) И константность структуры не делает константными её члены :-)

Делает :-) 7.1.6.1/4

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const

object during its lifetime (3.8) results in undefined behavior.

Как видишь, value_type имеет тип E, а не const E :-) Так что const_cast<E*> над const E* ничего плохого не делает :-) По идее :-)

Делает :-) Это undefined behaviour в силу 18.9/2

An object of type initializer_list<E> provides access to an array of objects of type const E.

и 7.1.6.1/4 выше.

Цепепе он такой :-) Сюрприз на сюрпризе :-) Прошу прощения за шум :-) Всем пока! :-)

anonymous
()
Ответ на: комментарий от anonymous

Все правильно делаешь, теперь почитай про decltype.

if e is an unparenthesized id-expression or a class member access (5.2.5), decltype(e) is the type of the entity named by e.

У тебя unparenthesized id-expression. И decltype тебе отдал ровно то, что написано в объявлении, а не то, чем оно является в контексте.

Kuzy ★★★
()
Ответ на: комментарий от anonymous

Не, я не против, если кто-то реально докажет, что это UB :-) Мне самому интересно, а штудировать стандарт не охота на эту тему :-)

7.1.6.1/4 и 18.9/2 стандарта доказывают это.

anonymous
()
Ответ на: комментарий от Kuzy

И decltype тебе отдал ровно то, что написано в объявлении, а не то, чем оно является в контексте.

А вот тут ты уже не прав :-) decltype(e) возвращает тип выражения e, только и всего :-) decltype((e)) вообще нужен для лямбд, ты его тут не тули :-)

anonymous
()
Ответ на: комментарий от anonymous

Да иди разберись уже.

decltype(e) возвращает тип выражения e

Нет, он возвращает тип выражения, только тогда когда оно не unparenthesized id-expression и не class member access. В этих двух случаях, оно возвращает тип который был указан при объявлении.

Если ты добавляешь вокруг скобки, то это уже никак не unparenthesized id-expression или class member access. Только и всего. Можно вместо скобок, например так написать: decltype(*(&a.foo))

Соответственно с помощью decltype(id) ты НЕ МОЖЕШЬ узнать какой тип у id в этом контексте. Тебе нужен decltype((id)).

struct F {
  int t;

  void foo() const {
    decltype(t) f; // int, как в объявлении
    decltype((t)) g; // const int&, потому что метод foo константный и в нем нельзя t изменять, это и есть тип выражения t
  }
}

Иди почитай последнюю книжку Мейерса или стандарт.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Нет, он возвращает тип выражения, только тогда когда оно не unparenthesized id-expression и не class member access.

Выражение - это по-английски expression, а по C++, expression включает и rvalue, и lvalue - раздел 3.10 стандарта :-) И e, и (e) - это выражения, если что :-) И не важно, parenthesized или unparanthesized оно :-) И то, что e может быть именем переменной, не отменяет того, что e - выражение :-) Вот и Мейерс пишет об этом: «Names are lvalue expressions, but that doesn’t affect decltype’s behavior. For lvalue expressions more complicated than names, however, decltype ensures that the type reported is always an lvalue reference.» :-)

Теперь стандарт: «if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e.»

«otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e» Т.е. если e - это выражение в скобках, то decltype(e) всегда T&, где T - тип e :-) Чего ты мне пытаешься доказать то? :-)

anonymous
()
Ответ на: комментарий от anonymous

Т.е. если e - это выражение в скобках, то decltype(e) всегда T&, где T - тип e :-) Чего ты мне пытаешься доказать то? :-)

Тип a.foo - const int. Поскольку decltype((a.foo)) отдает const int&.

decltype(a.foo) использовать в твоем примере не корректно (он возвращает «type of the entity named by e», то есть тоже что и decltype(A::foo)).

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

С ним бесполезно спорить, не утруждай себя. Все верные аргументы уже были приведены.

vzzo ★★★
()
Последнее исправление: vzzo (всего исправлений: 1)
Ответ на: комментарий от Kuzy

Тип a.foo - const int

Бугага :-) Нет! :-) Ты запутался в этом цепепе, что не удивительно :-) Тип A::foo - int :-)

struct A {
  int foo = 0;
};
Где ты видишь const int? :-) Объявление
const A a;
не меняет тип A::foo :-) Просто this в контексте a становится константным :-) Но тип A::foo - int :-) А то, что decltype((e)) всегда возвращает *ссылку*, которую ты отождествляешь с lvalue, то тебе об этом сказано в стандарте: «otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;» - т.е. decltype(e) возвращает тип T&, в то время как e имеет тип T :-) К чему ты приплёл вот это твоё

Ау, чудо, тебе нужен тип lvalue а не объявления. Используй decltype(()).

совершенно не понятно :-) lvalue - это от «left value», а «left value» - это значит «то, что слева от оператора присваивания» :-) Т.е. в выражении const A a; - a - lvalue, запомни это :-) Но ты *отождествляешь* ссылку, т.е. reference, с lvalue, а это совсем разные вещи :-) Ссылка, по своей природе, *обязана* быть инициализирована lvalue :-) Константная ссылка *может* быть инициализирована rvalue :-) Т.е. decltype((e)) - это про способ гарантировано получить тип T&, где e - всегда имеет тип T :-) Я ещё раз убедился, что цепепе - это мерзкий языконка с уродливой, слишком контексто-зависимой семантикой, который никто толком не знает :-)

anonymous
()
Ответ на: комментарий от anonymous

Тип a.foo - const int

Бугага :-) Нет! :-) Ты запутался в этом цепепе, что не удивительно :-) Тип A::foo - int :-)

Мде. Ты еще и путаешь a.foo с A::foo. Или опять не понимаешь, что написано.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Мде. Ты еще и путаешь a.foo с A::foo. Или опять не понимаешь, что написано.

Давай ещё раз разберём что написано в стандарте: «if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e.» Если e - выражение не в скобках, или обращение к члену класса без взятия его в скобки, то decltype(e) возвращает тип сущности, именованной как e. Следовательно, decltype(a.foo) - возвращает тип сущности, именованной как a.foo, т.е. int :-) Возражения будут? :-)

anonymous
()
Ответ на: комментарий от anonymous

Даже лень считать сколько раз за тред ты передернул. Но все таки напомню тебе, что речь шла о типе ВЫРАЖЕНИЯ, а не о результате decltype. А сам decltype не всегда возвращает тип выражения. Ты его использовал неправильно и он тебе вернул не тип выражения, а тип указанный в определении.

Kuzy ★★★
()
Ответ на: комментарий от anonymous

Нет конечно, я слишком глуп для этого.

Kuzy ★★★
()
Ответ на: комментарий от anonymous

otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e

Ау, чудо, тебе нужен тип lvalue а не объявления

if e is an lvalue

is an lvalue

А ты уже разобрался как переводиться is?

Давай еще раз.

e is an lvalue
T is the type of e

e is an lvalue
T is the type of e

И еще раз!

e is an lvalue
T is the type of e

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Но все таки напомню тебе, что речь шла о типе ВЫРАЖЕНИЯ

Нет такого понятия «тип выражения» :-) Есть понятие «тип данных» :-)

А сам decltype не всегда возвращает тип выражения.

Да что ты говоришь :-) Давай откроем грамматику, раздел 7.1.6.2:

decltype-specifier:
decltype ( expression )
decltype ( auto )

Что же означает слово «expression»? :-) Случайно, не выражение? :-) И далее по тексту стандарта:

For an expression e, the type denoted by decltype(e) is defined as follows:

decltype всегда возвращает тип данных, а не тип выражения :-)

Ты его использовал неправильно и он тебе вернул не тип выражения, а тип указанный в определении.

Я его правильно использовал, ибо мне нужен тип члена A, т.е.

if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e.

:-)

anonymous
()
Ответ на: комментарий от Kuzy

Точно, первое это class member access, а второе unparenthesized id-expression. Спасибо, учитель.

Нет :-) Как раз a.foo - это «unparenthesized class member access» :-) A::foo - это просто запись, чтобы обозначить член foo структуры A :-)

anonymous
()
Ответ на: комментарий от Kuzy

Ты очень крутой.

Нет, это ты очень крутой :-) Из-за тебя всё-таки пришлось лезть в стандарт и на cppreference.com :-) В общем, вся суть в том, что выражение (a.foo) *в контексте decltype* означает «ordinary lvalue expression» (пруф) :-) Но так только *в контексте decltype*, и больше нигде :-) По крайней мере, я больше нигде не видел в стандарте, что где-то в другом месте выражение в скобках имеет несколько иной смысл, нежели чем вне скобок :-) Т.е. вот код, в котором auto&& и auto выводят абсолютно одинаковые типы, вне зависимости от окружающих скобок в lvalue/rvalue:

#include <type_traits>

struct A {
  int foo = 0;
};

template<typename T, typename P>
void check_types(T&&, P&&)
{
  static_assert(std::is_same<T, P>::value, "");
}

int main(int argc, char *argv[])
{
  const A a;

  auto&& foo1 = a.foo;                           // тип const int&
  auto&& foo2 = (((a.foo)));                     // тип const int&
  auto&& (foo3) = a.foo;                         // тип const int&
  auto&& (foo4) = (a.foo);                       // тип const int&
  auto&& ((((((((((foo5)))))))))) = (((a.foo))); // тип const int&

  check_types(foo1, foo2);      // ok
  check_types(foo1, foo3);      // ok
  check_types(foo1, foo4);      // ok
  check_types(foo1, foo5);      // ok

  auto bar1 = a.foo;                           // тип int&
  auto bar2 = (((a.foo)));                     // тип int&
  auto (bar3) = a.foo;                         // тип int&
  auto (bar4) = (a.foo);                       // тип int&
  auto ((((((((((bar5)))))))))) = (((a.foo))); // тип int&

  check_types(bar1, bar2);      // ok
  check_types(bar1, bar3);      // ok
  check_types(bar1, bar4);      // ok
  check_types(bar1, bar5);      // ok

  return 0;
}

Ой вей, какой, всё таки, цепепе контекстно-зависимый язык :-) Какой очевидный, и всем интуитивно понятный :-) Зубрить лет 10, потом работать с удовольствием :-) Лол :-)

PS. Я, пожалуй, завязываю с C++ :-) Он отнимает слишком много моего времени :-)

anonymous
()
Ответ на: комментарий от Kuzy

Есть варинты лучше?

Ну вот я и спрашиваю, как принято(:

deadskif
() автор топика
17 апреля 2017 г.
Ответ на: комментарий от anonymous

сука ебало бы тебе вскрыть черт проклятый

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.