610 / 415 / 151
Регистрация: 11.01.2019
Сообщений: 1,745
1

Выбор основного шаблона и специализации

08.05.2021, 15:05. Показов 960. Ответов 3

Всем привет!
Подкину вам задачку... Я пока не раскусил, почему так происходит: типы DefaultType и ValueType должны быть одинаковые, но выбирается почему-то основной шаблон, а не специализация, из-за чего l-value ссылки обрабатываются неверно. Задача состоит в написании функции присваивания элементу std::tuple нового значения по рантайм-индексу.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
template <typename DefaultType, typename ValueType>
struct ValueOrDefault
{
    DefaultType operator()(const ValueType& value) const
    {
        (void)value;
        return DefaultType();
    }
};
 
template <typename ValueType>
struct ValueOrDefault<ValueType, ValueType>
{
    ValueType&& operator()(ValueType&& value) const
    {
        return std::forward<ValueType>(value);
    }
};
 
template <std::size_t Index = 0, typename ValueType, typename... EntryTypes>
inline typename std::enable_if<Index == sizeof...(EntryTypes), void>::type
AssignTupleEntry(std::tuple<EntryTypes...> &, int, ValueType&&)
{ }
 
template <std::size_t Index = 0, typename ValueType, typename... EntryTypes>
inline typename std::enable_if<Index < sizeof...(EntryTypes), void>::type
AssignTupleEntry(std::tuple<EntryTypes...>& t, int index, ValueType&& value)
{
    if (index == 0)
    {
        std::get<Index>(t) =
            ValueOrDefault<typename std::tuple_element<Index, std::tuple<EntryTypes...>>::type, ValueType>()(std::forward<ValueType>(value));
    }
    else
    {
        AssignTupleEntry<Index + 1, ValueType, EntryTypes...>(t, index - 1, std::forward<ValueType>(value));
    }
}
 
int main()
{
    auto t = std::make_tuple(1, 2, std::string("abc"), std::string("def"), 4.0f);
    int i = -1;
    std::string s1 = "456";
    std::string s2 = "789";
    AssignTupleEntry(t, 0, i); // не присваивается, т.к. используется основной шаблон ValueOrDefault
    AssignTupleEntry(t, 1, -2);
    AssignTupleEntry(t, 2, std::string("123"));
    AssignTupleEntry(t, 2, s1); // не присваивается, т.к. используется основной шаблон ValueOrDefault
    AssignTupleEntry(t, 3, std::move(s2));
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.05.2021, 15:05
Ответы с готовыми решениями:

Извлечь тип из специализации шаблона
template&lt;class T&gt; class cl { public: T t; cl(){ type t2; } }; ...

Ошибка при специализации шаблона
Пишу: template &lt;&gt; struct Test &lt; int&gt; { Test(int x) :x(x) {} int Cout...

Вывод типа шаблона в частичной специализации
template &lt;typename T&gt; struct DecayT { }; template &lt;typename R, typename T&gt; // почему R...

О специализации шаблона: почему код компилируется?
Добрый день. Вроде бы, по правилам специализации шаблонов, можно только уточнять поведение...

3
16079 / 8681 / 2120
Регистрация: 30.01.2014
Сообщений: 14,960
08.05.2021, 15:41 2
Лучший ответ Сообщение было отмечено jugu как решение

Решение

Цитата Сообщение от jugu Посмотреть сообщение
почему так происходит:
Потому что при передаче lvalue int и std::string тип ValueType выводится как int&, и std::string& соответственно.

Кликните здесь для просмотра всего текста
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
template <typename DefaultType, typename ValueType>
struct ValueOrDefault
{
    DefaultType operator()(const ValueType& value) const
    {
        (void)value;
        return DefaultType();
    }
};
 
template <typename ValueType>
struct ValueOrDefault<ValueType, ValueType>
{
    template <typename T>
    T&& operator()(T && value) const
    {
        return std::forward<T>(value);
    }
};
 
template <std::size_t Index = 0, typename ValueType, typename... EntryTypes>
inline typename std::enable_if<Index == sizeof...(EntryTypes), void>::type
AssignTupleEntry(std::tuple<EntryTypes...> &, int, ValueType&&)
{ }
 
template <std::size_t Index = 0, typename ValueType, typename... EntryTypes>
inline typename std::enable_if<Index < sizeof...(EntryTypes), void>::type
AssignTupleEntry(std::tuple<EntryTypes...>& t, int index, ValueType&& value)
{
    if (index == 0)
    {
        using PureValueT = std::remove_cv_t<std::remove_reference_t<ValueType>>;
        using TupleValueT = std::tuple_element_t<Index, std::tuple<EntryTypes...>>;
        
        std::get<Index>(t) = ValueOrDefault<TupleValueT, PureValueT>()(std::forward<ValueType>(value));
    }
    else
    {
        AssignTupleEntry<Index + 1>(t, index - 1, std::forward<ValueType>(value));
    }
}
 
int main()
{
    auto t = std::make_tuple(1, 2, std::string("abc"), std::string("def"), 4.0f);
    int i = -1;
    std::string s1 = "456";
    const std::string s2 = "789";
    AssignTupleEntry(t, 0, i); // не присваивается, т.к. используется основной шаблон ValueOrDefault
    AssignTupleEntry(t, 1, -2);
    AssignTupleEntry(t, 2, std::string("123"));
    AssignTupleEntry(t, 2, s1); // не присваивается, т.к. используется основной шаблон ValueOrDefault
    AssignTupleEntry(t, 3, std::move(s2));
    return 0;
}
0
610 / 415 / 151
Регистрация: 11.01.2019
Сообщений: 1,745
08.05.2021, 16:12  [ТС] 3
Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что при передаче lvalue int и std::string тип ValueType выводится как int&, и std::string& соответственно.
Почему тогда с r-value всё нормально проходит? Ведь int и std::string выводятся как int&& и std::string&& ... Или нет?
0
16079 / 8681 / 2120
Регистрация: 30.01.2014
Сообщений: 14,960
08.05.2021, 16:43 4
Цитата Сообщение от jugu Посмотреть сообщение
Или нет?
Нет.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.05.2021, 16:43
Помогаю со студенческими работами здесь

Ведет ли к инстанцированию определение явной специализации шаблона функции?
сабж ясен из заголовка

Вывод типа шаблона в частичной специализации, с вариативными параметрами в стиле Си
в книге есть код: template &lt;typename R, typename... Args&gt; struct DecayT &lt;R(Args...) &gt; { ...

Ошибка "использование списка аргументов шаблона в объявлении основного шаблона не допускается"
Я где-то видел подобную класс template&lt;typename T&gt; class sml&lt;4, T&gt; {...} Но когда я пытаюсь...

Генерация бинарного кода функции или инстанциирование при определении явной специализации шаблона функции
Заранее прошу прощение, если буду использовать не совсем точную терминологию. Буду рад, если...

Шаблон спецификации основного шаблона
Добрый день у меня возник вопрос. Вот мой код: template&lt;int SIZE, typename T&gt; class MANIP_zv...

Возврат объекта шаблонного типа от типа Type из специализации шаблона метода от того же типа
Доброго времени суток, пишу класс содержащий несколько std::set от разных типов, нужно сделать...


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru