Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
1 / 1 / 0
Регистрация: 04.12.2015
Сообщений: 71
1

Компилятор не может вывести тип для темплейта, передаваемого в вектор

03.07.2017, 23:49. Показов 1648. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Не работает такая вот конструкция:
C++
1
template<typename T> T getRandomElement(std::vector<T> v) { return v[getRandom(0, v.size() - 1)]; }
getRandom(int a, int b) возвращает число от a(включительно) до b(включительно).

Компилируется без ошибок, но вот любая попытка использования выдает ошибку.
Проблема в том, что почему-то не подхватывается возвращаемое значение.
Собственно, ошибка:
error C2783: 'T1 getRandomElement(std::vector<_Ty,std::allocator<_Ty>> &)': could not deduce template argument for 'T1'

Что я делаю не так и как заставить это работать? Нет, можно, конечно, сделать тип void, а возвращаемое вытаскивать через запись в переменную, которую сделать вторым аргументом функции, но хотелось бы починить этот вариант, а не делать новый.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.07.2017, 23:49
Ответы с готовыми решениями:

Узнать тип объекта передаваемого по ссылке
Есть класс А, класс В наследник, в классе С в методе будет приходить объект по ссылке на базовый...

Как определить тип передаваемого объекта
Есть компонент с названием simpleOpenGlControl. Его нужно передать в функцию, но такое: public...

[решено] Компилятор и тип МК Код для нескольких МК в проекте
Всем привет. Подскажите новичку. Пишу код под два контроллера Atmega16 и Atmega 328 //...

Компилятор не знает тип ushort
Здравствуйте. Увидел тип ushort в учебнике,сперва не понял,что за тип такой,но потом узнал,что...

18
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.07.2017, 00:03 2
Цитата Сообщение от Siborgium Посмотреть сообщение
Что я делаю не так
пытаетесь объяснять на пальцах всякую фигню,
вместо того, что бы просто привести кодом
минимальный пример-иллюстрацию вашей проблемы.

Цитата Сообщение от Siborgium Посмотреть сообщение
как заставить это работать?
показать код.
0
1 / 1 / 0
Регистрация: 04.12.2015
Сообщений: 71
04.07.2017, 00:06  [ТС] 3
Цитата Сообщение от hoggy Посмотреть сообщение
показать код.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<cstdlib>
#include<iostream>
#include<vector>
#include<random>
 
int getRandom(int from, int to) {
    std::mt19937 rng; rng.seed(std::random_device()());
    std::uniform_int_distribution<std::mt19937::result_type> dist(from, to);
    return dist(rng);
}
 
template<typename T> T getRandomElement(std::vector<T> v) { T a = v[getRandom(0, v.size() - 1)]; return a; }
int main(int argc, char* argv[]){
    std::cout << getRandomElement({ "a","b","c","d" }) << std::endl;
    system("pause");
    return 0;
}
Все. Ничего более, серьезно.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.07.2017, 00:27 4
Цитата Сообщение от Siborgium Посмотреть сообщение
Ничего более, серьезно.
вы всерьёз считаете,
что компилятор должен был догадаться,
что { "a","b","c","d" } - это вектор интов?
0
1 / 1 / 0
Регистрация: 04.12.2015
Сообщений: 71
04.07.2017, 00:28  [ТС] 5
Где вы увидели, что это вектор интов? В указанном коде я передаю туда const char*, не int.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.07.2017, 00:43 6
Лучший ответ Сообщение было отмечено Siborgium как решение

Решение

http://rextester.com/GSHA48375

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<cstdlib>
#include<iostream>
#include<vector>
#include<random>
 
 
using type = std::mt19937::result_type;
 
type getRandom(type from, type to) 
{
    std::mt19937 rng; 
    rng.seed(std::random_device()());
    std::uniform_int_distribution<std::mt19937::result_type> dist(from, to);
    return dist(rng);
}
 
template<typename T>
auto getRandomElement(const std::initializer_list<T>& v)     
{ 
    return v.begin()[ getRandom(0, v.size() - 1) ];
}
 
int main(int argc, char* argv[])
{
    (void)argc;
    (void)argv;
    
    std::cout << getRandomElement({ "a","b","c","d" }) << std::endl;
    std::cout << getRandomElement({1,2,3,4})           << std::endl;
}
1
1 / 1 / 0
Регистрация: 04.12.2015
Сообщений: 71
04.07.2017, 00:49  [ТС] 7
Благодарю, разобрался.
0
Croessmah
05.07.2017, 18:03
  #8

Не по теме:

hoggy, только генератор бы в thread_local запхнуть.

0
dawn artist
05.07.2017, 18:29
  #9

Не по теме:

Цитата Сообщение от Croessmah Посмотреть сообщение
только генератор бы в thread_local запхнуть.
Согласен. mt19937 — довольно тяжёлая вещь, чтобы её так вот при каждом вызове создавать-уничтожать. Ещё и std::random_device постоянно создаётся, который тоже не быстр, т.к. обычно иницирует I/O или ещё как-то дёргает систему за сисколы.

0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
05.07.2017, 18:38 10
Croessmah,
Тут же один поток, зачем тред локал?
0
Croessmah
05.07.2017, 19:52
  #11

Не по теме:

Undisputed, сегодня один, завтра два. Да и дело не в потоках. Постоянно seed переделывать зачем?

0
Undisputed
06.07.2017, 08:39
  #12

Не по теме:

Croessmah,
Понятно, а нельзя сделать тоже самое через static переменную внутри функции?

0
Croessmah
06.07.2017, 09:10
  #13

Не по теме:

Цитата Сообщение от Undisputed Посмотреть сообщение
Понятно, а нельзя сделать тоже самое через static переменную внутри функции?
пока один поток - можно. А можно сразу сделать thread_local и получить фактически, то же самое.

0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
06.07.2017, 09:25 14
hoggy,
Много раз уже видел в кодах приведение к void без присваивания результата переменной как вы написали выше
C++
1
(void)argc
Для чего применяются такие вещи? Я пока думаю что это нужно если для класса определён operator void и он например выполняет какую то глобальную настройку...
0
18895 / 9853 / 2410
Регистрация: 30.01.2014
Сообщений: 17,296
06.07.2017, 09:38 15
Undisputed, этот прием используется для подавления warning`а о неиспользуемой переменной. Иногда оборачивают в макрос к говорящим названием для придания большей декларативности.
C++
1
2
3
4
5
6
#define UNUSED(a) (void)(a)
///.....
void foo(int arg)
{
    UNUSED(arg);
}
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
06.07.2017, 10:16 16
DrOffset,
Ясно, спасибо!
А не проще просто не объявлять переменные которые не собираемся использовать?
0
18895 / 9853 / 2410
Регистрация: 30.01.2014
Сообщений: 17,296
06.07.2017, 10:25 17
Цитата Сообщение от Undisputed Посмотреть сообщение
А не проще просто не объявлять переменные которые не собираемся использовать?
Ну если у тебя сигнатура функции такая, что там есть аргументы, но они в данный момент не используются, то это может быть актуально. Например, при переопределении виртуальной функции, часть аргументов которой не нужны в текущем варианте. В принципе в С++ можно просто оставить такой аргумент без имени. Но надо понимать, что этот паттерн очень старый, еще со времен С. А в С нельзя было оставлять аргументы функций неименованными.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
06.07.2017, 10:39 18
DrOffset,
Ясно, насчёт переопределении функций думается мне что решение не очень... Потому что вызывающая сторона вынуждена передавать неиспользуемый аргумент, а это только усложняет код и тратит хоть и мало но лишние ресурсы... Наверное в таких случаях лучше было бы перегрузить функцию и задать нужное количество аргументов вместо того что бы переопределять ее с лишними параметрами. Или виртуальные методы не перегружаются/возникают проблемы в этих случаях?
0
18895 / 9853 / 2410
Регистрация: 30.01.2014
Сообщений: 17,296
06.07.2017, 11:44 19
Цитата Сообщение от Undisputed Посмотреть сообщение
Или виртуальные методы не перегружаются/возникают проблемы в этих случаях?
Перегружаются, но если в базовом классе нет перегрузки, то ты добавлением таковой в наследнике ничего не решишь, она вызываться-то не будет

Вообще, надо сказать, что когда такое случается - это может (но не обязательно) говорить о кривом дизайне интерфейса, но мы же живем в реальном мире, а в реальном мире такое встречается. Поэтому если уж у тебя есть такой интерфейс, который оказывается избыточным для какого-то из наследников, то менять базовый класс для добавления туда перегрузки не всегда удастся безболезненно, если вообще будет возможным.
1
06.07.2017, 11:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.07.2017, 11:44
Помогаю со студенческими работами здесь

Компилятор не понимает тип Array
Подскажите почему ругаеться на Array вот код #define MATRIX_H #include &lt;iostream&gt; #include...

Компилятор не может определить идентификатор
есть небольшой кодик, который расшифровывает устройства PCI, код написан на си под линукс, я же...

Почему компилятор не распознает тип ofstream?
Почему не определяет ofstream хотя библиотека #include &quot;fstream&quot; есть П.5.18.Правил Запрещено...

Компилятор не опознает пользовательский тип данных
Не понимаю, почему не компилируется, вроде все делаю правильно, а ошибка вот в этой строке AUZ a;...

Компилятор криво обрабатывает тип string
В общем, такое дело. Я начинающий кодер и очень долго терплю одну проблему, связанную с...

Почему компилятор не понимает тип bool?
#include &lt;stdio.h&gt; #include &lt;iostream .h&gt; #include &lt;fstream.h&gt; #include &lt;iomanip.h&gt; #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru