#c #templates
#c #шаблоны
Вопрос:
Минимальный воспроизводимый пример
#include <unordered_map>
#include <string>
template<class T, bool did_work>
class Test {
Test(T input) : field(input), success(did_work) {}
T field;
bool success;
};
template<typename A>
void func(std::unordered_map<std::string, Test<A, bool>> input1, A input2) {}
int main() {}
Вывод:
$ g -std=c 17 -ggdb -g3 -Wall test.cpp amp;amp; ./a.out
test.cpp:12:51: error: type/value mismatch at argument 2 in template parameter list for ‘template<class T, bool did_work> class Test’
12 | void func(std::unordered_map<std::string, Test<A, bool>> input1, A input2) {}
| ^~~~
test.cpp:12:51: note: expected a constant of type ‘bool’, got ‘bool’
test.cpp:12:55: error: template argument 2 is invalid
12 | void func(std::unordered_map<std::string, Test<A, bool>> input1, A input2) {}
| ^~
test.cpp:12:55: error: template argument 5 is invalid
Мне нужно иметь возможность передавать, unordered_map<std::string, Test<A, true>>
а также unordered_map<std::string, Test<A, false>>
. Есть ли способ сделать это в определении функции без изменения определения класса Test
?
Ответ №1:
With template<class T, bool did_work>
did_work
— параметр шаблона, отличающийся от типа. Это означает, что вместо передачи ему типа он принимает значение. Поскольку для этого требуется значение, вы делаете Test
like Test<A, true>
или Test<A, false>
, not Test<A, bool>
.
Для вашей функции вы можете просто добавить параметр шаблона, отличающийся от типа, чтобы сделать это по своему усмотрению
template<typename A, bool did_work>
void func(std::unordered_map<std::string, Test<A, did_work>> input1, A input2) {}
Комментарии:
1. итак, нет ли способа обойти это, не определив два экземпляра функции, один из которых принимает
Test<A, false>
, а другой принимаетTest<A, true>
?2. @ajoseps Только что добавил в ответ, показывающий, как настроить шаблон для использования обоих.
Ответ №2:
Сделайте это так:
#include <unordered_map>
#include <string>
template<class T, bool did_work>
class Test {
Test(T input) : field(input), success(did_work) {}
T field;
bool success;
};
template<typename A, bool b = true>
void func(std::unordered_map<std::string, Test<A, b>> input1, A input2)
{
}
int main() {
}
Обновить
Я имею в виду, что вы пишете что-то вроде:
#include <unordered_map>
#include <string>
#include <iostream>
template<class T, bool did_work>
class Test {
public:
Test(T input) : field(input), success(did_work) {}
private:
T field;
bool success;
};
template<
typename UnorderedMap
,typename A
> requires requires (UnorderedMap map){
map.size();
}
void func(
UnorderedMap input1,
A input2)
{
std::cout << input1.size();
}
int main()
{
using A = int;
Test<A, true> t{12};
std::unordered_map<std::string, Test<A, true>> map{};
func(map, 12);
//this would fail!
//func(12, 12);
}
Комментарии:
1. Но в целом вам следует избегать таких строгих требований к типу. Я бы выбрал концепции / ограничения или SFINAE, если у вас есть какие-то требования.
2. не возражаете ли вы расширить понятия / ограничения или подход SFINAE? Я не слишком хорошо знаком с ними
3. Кроме того, вы не должны использовать параметры «по значению» для контейнеров — это может быть дорого…
4. можете ли вы объяснить, почему это может быть дорого?
5. Если вы переносите большие объекты по значению, вам может потребоваться скопировать много данных