LINUX.ORG.RU

Почему не выодится тип

 


0

2
struct W{
	template <typename T>
		W(int s, T &&t) {}
	template <typename T>
		W(T &&t) {}
};

int main() {
   W w1( {4} );    // ok
   W w2( 4, {4} ); // error (couldn’t deduce template parameter ‘T’)
	return 0;
}

Может туплю, но не вижу никаких причин для отказа в выводе здесь.

★★

Как обычно споришь с компилятором, а потом жалуешься на форуме, вместо того что бы делом заниматься?

Aswed ★★★★★
()

потому что ты используешь copy-list инициализацию для которой нет конструктора

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

Вообще хорошо, что не работает. Тогде не ясно, что это за исключение, которое пропускается:

W w1( {4} );    // ok
pavlick ★★
() автор топика
Ответ на: комментарий от pavlick
W w1( {4} );

интерпретируется как

W w1( W(4) );

Можно добавить W(const W&) = delete;, чтобы оно перестало компилироваться.

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

W w1( {4} ); интерпретируется как W w1( W(4) );

Спасибо, мы это и без тебя знаем. Покажи в стандарте с чего это вдруг происходит.

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

Вообще нет, {4} это не тип, поэтому компилятор ищет шаблон куда это можно проинстанцировать, т.е. {4} отлично притягивается к int, в его случае в обоих случаях будет браться шаблон W(int s, T &&t) {}

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

Точно, я из-за двух конструкторов и не догадался как-то. Ну тогда все норм и логично.

Всем спасибо.

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

Точно, я из-за двух конструкторов и не догадался как-то. Ну тогда все норм и логично.

Ну если логично, то расскажи, какие пункты в стандарте говорят что

W w1( {4} ); интерпретируется как W w1( W(4) );

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

До list initialization ещё добраться надо. Из braced-init-list тип не выводится. Т.е. из {4} T не вывести как int.

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

Покажи в стандарте с чего это вдруг происходит.

Всё, сам нашёл. Надо было чуть внимательнее на грамматику посмотреть. Пропустил, что braced-init-list это тоже expression-list (т.е. первый является продукцией последнего).

Это C++17/20 [dcl.init]/(17.6.2) + [over.match.ctor]/1 (сначала подумал, что последнее предложение из [over.match.ctor]/1 не распространяется на braced-init-list).

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

Если вопрос в таком ключе, то ни в один, потому что сначала необходимо выполнить инстанцирование шаблона, а потом в 11

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

сначала необходимо выполнить инстанцирование шаблона

Ну и почему, по-твоему, в W w2( 4, {4} ) T должен вывестись из {4} как int, если braced-init-list это non-deduced context (т.е. из него аргументы шаблона не выводятся)?

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

Ладно, похоже, окончательно разобрался. При превращении W({4}) в W(W{4}) нужно «пройти» через [dcl.init] и [over]/[temp] не один раз. Я сначала подумал что W{4} получится при первом (и единственном) «попадании» в [over]/[temp].

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

Ну если конкретно про этот случай, то тут вроде понятно - это. Один converting конструктор идет за одну user cast. Но вот в другое я не въехал:

struct S {
	int i;
	int a;
	operator int() {return 0;}
};
struct W {
		W(int t) {}
};
int main() {
   S s;
   W w{s};
}

по идее тут попадаем в то же пункт стандарта (т.к. destanation - класс), и так как подходящих конструкторов нет, то должно по идее следовать

If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

Но почему-то компилится и попадаем на следующий 17.7 пункт. Я так и не понял этого момента.

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

Ну если конкретно про этот случай, то тут вроде понятно - это.

Это-то понятно)))

Но что получится при

The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution.

???

Я, например, сначала неправильно подумал. Посмотрим, что ты думаешь.

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

Точнее, так: какой список конструкторов получим в первый раз при

The applicable constructors are enumerated ([over.match.ctor])

после (попытки) инстанциации шаблонов и отсеивания явно не подходящих по числу аргументов?

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

W w{s};
по идее тут попадаем в то же пункт стандарта (т.к. destanation - класс)

Попадаем в самый первый пункт:

If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized.

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

Спорить не буду, но мне кажется, что там какие-то нестыковки. На цппреференс подобная ремарка есть

Order of the conversions

...

When considering the argument to a constructor or to a user-defined conversion function, only a standard conversion sequence is allowed (otherwise user-defined conversions could be effectively chained).
pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Спорить не буду, но мне кажется, что там какие-то нестыковки. На цппреференс подобная ремарка есть

Я думаю «нестыковки» возникают когда ты пытаешься читать перепевы Рабиновича вместо стандарта. Видимо, имеется в виду это правило и условия в твоём примере для срабатывания этого правила не выполняются.

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

Спасибо за ссылки. Кажется начинаю понимать разницу между {…} и {{…}}. Не как бы и раньше знал )), но вот на сухом, формальном уровен не улавливал.

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

Да, всё правильно, что он не выводится автоматом. Причина затруднений в неожиданности трансформации C{{x,y,z}} в C{x,y,z}, не знаю точно, может это очень нужно (хотя честно говоря сомневаюсь, может лучше бы вообще из стандарта это вычеркнуть?), но меня с толку это сбило (это вылилось в разный наблюдаемый результат без возможности найти объяснение не зная этой фичи).

Ещё, кстати, не совсем понятно - в цпп20 разрешили агрегатную инициализацию через () - с возможностью narrow conversion, отлично, буду пользоваться вместо {} в некоторых случаях. Но вот продление жизни prvalue вкрутить забыли?

struct S{
   const int &r;
};
S s{5};  // ok
S s(5);  // dangling reference

превосходно

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

Причина затруднений в неожиданности трансформации C{{x,y,z}} в C{x,y,z}

У тя нет такой трансформации. Хотя бы потому, что C({x,y,z})

Но вот продление жизни prvalue вкрутить забыли?

Что такое продление жизни выражения?

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

У тя нет такой трансформации. Хотя бы потому, что C({x,y,z})

В смысле нет? Мы тут весь тред об этом толковали, что init-list идёт аргументом в конструктор destanation, а это означает, что запись C{{…}} превращается в C{…}

Что такое продление жизни выражения?

Ну понятно же о чем я, зачем придираться? Ок - продление жизни временного объекта материализованного из prvalue выражения.

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

В смысле нет? Мы тут весь тред об этом толковали, что init-list идёт аргументом в конструктор destanation, а это означает, что запись C{{…}} превращается в C{…}

Я думал ты про код в оригинальном OP-посте.

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

Просто потом вводится обратно.

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

{4} в с++14 выводится как int. посмотри список изменений между с++11 и с++14, в частности «New Rules for auto deduction from braced-init-list». разница в том, что {4} - это единственный элемент инициализации.

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

{4} в с++14 выводится как int. посмотри список изменений между с++11 и с++14, в частности «New Rules for auto deduction from braced-init-list».

Там изменения для вывода типа для auto. Добавили специальное правило.

разница в том, что {4} - это единственный элемент инициализации.

Разница в этом правиле в том, что 4 — единственный элемент списка.

К коду из ОП-поста изменения вывода типов для auto не относятся.

anonymous
()

ну сам возможно проверишь у себя вот такое:

`--> g++ main.cpp -std=c++17
main.cpp: В функции «int main()»:
main.cpp:2:20: ошибка: deducing from brace-enclosed initializer list requires «#include <initializer_list>»
  +++ |+#include <initializer_list>
    1 | int main() {
    2 |     auto res = { 4 };
      |                    ^


------------------------------------------------
`--> cat main.cpp

int main() {
    auto res = { 4 };

    return res;
}


и далее:
`--> g++ main.cpp -std=c++17
main.cpp: В функции «int main()»:
main.cpp:5:12: ошибка: cannot convert «std::initializer_list<int>» to «int» in return
    5 |     return res;
      |            ^~~

------------------------------------------------
`--> cat main.cpp

#include <initializer_list>
int main() {
    auto res = { 4 };

    return res;
}


я тут про то — какой тип создается из этого `{4}`

safocl ★★
()
Последнее исправление: safocl (всего исправлений: 3)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.