Можно ли как-то сделать специализацию функции шаблона вот так:
template<typename T, typename... Args>
void Func(size_t id, Args... args) { std::cout << "1\n" }
template<>
void Func<SomeClass>(size_t id, Args... args) { std::cout << "2\n" }
Поэтому я хочу оставить переменные аргументы Args, но указать T = SomeClass:
Func<A>(1, 2, 3); // 1
Func<SomeClass>(1, 2); // 2
Я знаю, что можно использовать "маленький хак" - обернуть func в класс и сделать для него частичную специализацию, но в моем случае это не работает, потому что Func() на самом деле является неким методом класса и он инициализирует некоторые члены этого класса . Таким образом, хак-класс должен иметь указатель на него и дружить с ним (поскольку члены являются частными), что также является проблемой.
А ещё этот хак выглядит немного пугающе и нечитабельно.
Просто напишите if constexpr
вместо специализации.
Это возможно, но вам придется добавить дополнительный первый аргумент, представляющий тип класса, на котором вы хотите специализироваться. И тогда вы можете использовать систему вывода типов C++, она будет соответствовать функции с наиболее конкретным соответствием (сначала обычная перегрузка функции).
#include <iostream>
#include <utility>
#include <type_traits>
struct A{};
struct SomeClass{};
struct MyClass
{
template<typename T, typename... Args>
void Func(const T&, std::size_t id, Args&&... args) // use rvalue references for args (avoids copying of temporaries)
{
std::cout << "id = " << id << ", args : ";
((std::cout << std::forward<Args>(args) << " "), ...); // C++17 fold expression use std::forward to keep "rvalue" reference(ness)
std::cout << "\n";
}
template<typename... Args>
void Func(const SomeClass&, std::size_t id, Args&&... args) // use rvalue references for args (avoids copying of temporaries)
{
std::cout << "SomeClass : ";
std::cout << "id = " << id << ", args : ";
((std::cout << std::forward<Args>(args) << " "), ...); // C++17 fold expression
std::cout << "\n";
}
};
int main()
{
A a{};
SomeClass s{};
MyClass c;
c.Func(a,1ul,1,2);
c.Func(s,1ul,1,2,3);
}
@user12002570 user12002570 Хм, да, исправил.
void
).
Можно ли как-то сделать специализацию функции шаблона вот так
Мы не можем частично специализировать шаблоны функций. Но есть способы добиться желаемого эффекта.
С помощью c++20 вы можете ограничить Func
, используя requires
, как показано ниже.
template<typename T, typename... Args>
void Func(std::size_t id, Args... args)
{
std::cout << "1\n";
}
//overload for SomeClass
template<typename T, typename... Args>
void Func(std::size_t id, Args... args) requires(std::is_same_v<T, SomeClass>)
{
std::cout << "2\n";
}
int main()
{
Func<A>(1, 2, 3); // 1
Func<SomeClass>(1, 2); // 2
}
Другая альтернатива — использовать constexpr if
, как показано ниже:
template<typename T, typename... Args>
void Func(std::size_t id, Args... args)
{
if constexpr(std::is_same_v<T, SomeClass>)
{
std::cout << "2\n";
}
else
{
std::cout << "1\n";
}
}
Я тоже думал об этом, но тогда вам нужно будет сначала удалить первый аргумент Args, если вы сможете использовать остальные аргументы (или SomeClass всегда будет первым типом аргумента)
@PepijnKramer Да, но это похоже на дополнительный вопрос, который ОП должен задать отдельно, если они этого хотят.
Вполне вероятно ;)
Поскольку шаблон функции не поддерживает частичную специализацию, вы можете перегрузить
Func
и ограничить его с помощьюrequires
, как показано здесь . Смотрите рабочую демо