Я пытаюсь реализовать шаблон класса со статическими функциями-членами, которые могут обрабатывать разные типы. Мой код выглядит следующим образом (очень упрощенный пример):
#include <array>
struct Foo {
template<typename T>
static constexpr size_t foo(T v);
};
template<>
constexpr size_t Foo::foo(double v) {
return sizeof(v);
}
template<int count>
constexpr size_t Foo::foo(const std::array<int, count>& v) {
return sizeof(int) * v.size();
}
Однако, когда я пытаюсь его скомпилировать, я получаю следующую ошибку:
<source>:16:23: error: out-of-line definition of 'foo' does not match any declaration in 'Foo'
16 | constexpr size_t Foo::foo(const std::array<int, count>& v) {
| ^~~
1 error generated.
Compiler returned: 1
Как я могу специализировать шаблон с помощью другого шаблона?
foo
объявлен в Foo
как шаблон метода с параметром типа (typename T
).
Первая специализация с параметром double
является допустимой специализацией этого шаблона.
Но ваш второй недействителен, потому что вы не можете специализировать шаблон функции/метода с параметром типа (typename T
) с параметром, не относящимся к типу (int count
) (такой вид частичной специализации возможен только для шаблонов классов).
Вместо этого вы можете просто добавить в Foo
еще один шаблон метода, который использует параметр, не являющийся типом:
#include <array>
#include <iostream>
struct Foo {
template<typename T>
static constexpr size_t foo(T v) {
return sizeof(v)+1;
}
// Added: a version with non-type parameter:
template<size_t count>
static constexpr size_t foo(const std::array<int, count>& v) {
return sizeof(int) * v.size();
}
};
template<>
constexpr size_t Foo::foo(double v) {
return sizeof(v);
}
int main()
{
// Use the non-type parameter version:
std::cout << Foo::foo<3>({ 1,2,3 }) << std::endl;
// Use the specialized type parameter version:
std::cout << Foo::foo<double>(1.1) << std::endl;
// Use the default type parameter version:
std::cout << Foo::foo<int>(123) << std::endl;
}
Выход:
12
8
5
Примечание: нетиповой параметр count
, имеющий размер std::array
, должен быть size_t
(а не int
).
«Но ваш второй недействителен, потому что вы не можете специализировать шаблон с параметром типа (имя типа T) с параметром, не относящимся к типу (int count)». Это частичная специализация, которую можно реализовать только с помощью шаблонов классов, но не с помощью шаблонов функций.
@ 463035818_is_not_an_ai Я не понял. Первая специализация также относится к функции, а не к классу, но это нормально, поскольку она специализируется на типе.
посмотрите здесь, что я имею в виду: godbolt.org/z/h7Wcjo1xj. Ваше утверждение неверно. Вы можете написать частичную специализацию с параметром, не относящимся к типу, для шаблона с параметром типа. Но только шаблоны классов допускают частичную специализацию.
@463035818_is_not_an_ai теперь я понимаю. Обновлено соответственно.
Для шаблонов функций не существует частичной специализации, но вы можете частично специализировать шаблон класса:
#include <array>
#include <cstddef>
template <typename T> struct Foo_impl;
template <> struct Foo_impl<double> {
constexpr static size_t value = sizeof(double);
};
template <size_t count> struct Foo_impl<std::array<int,count>> {
constexpr static size_t value = count * sizeof(int);
};
struct Foo {
template<typename T>
static constexpr size_t foo(T v) {
return Foo_impl<T>::value;
}
};
Также обратите внимание, что вы должны использовать правильный тип, а не size_t
.
Думаю, вы пропустили sizeof(int)
по второй специализации.
@LoS действительно, хотя для вопроса это не существенно. Спасибо, исправил
Вы не можете частично специализировать функцию-член шаблона как для функции-члена типа шаблона, так и для функции-члена не-типа.