Специализируйте шаблон метода с параметром типа с нетиповым параметром

Я пытаюсь реализовать шаблон класса со статическими функциями-членами, которые могут обрабатывать разные типы. Мой код выглядит следующим образом (очень упрощенный пример):

#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

Как я могу специализировать шаблон с помощью другого шаблона?

Вы не можете частично специализировать функцию-член шаблона как для функции-члена типа шаблона, так и для функции-члена не-типа.

floatfoo 19.06.2024 14:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
102
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Live demo

Примечание: нетиповой параметр count, имеющий размер std::array, должен быть size_t (а не int).

«Но ваш второй недействителен, потому что вы не можете специализировать шаблон с параметром типа (имя типа T) с параметром, не относящимся к типу (int count)». Это частичная специализация, которую можно реализовать только с помощью шаблонов классов, но не с помощью шаблонов функций.

463035818_is_not_an_ai 19.06.2024 14:28

@ 463035818_is_not_an_ai Я не понял. Первая специализация также относится к функции, а не к классу, но это нормально, поскольку она специализируется на типе.

wohlstad 19.06.2024 14:30

посмотрите здесь, что я имею в виду: godbolt.org/z/h7Wcjo1xj. Ваше утверждение неверно. Вы можете написать частичную специализацию с параметром, не относящимся к типу, для шаблона с параметром типа. Но только шаблоны классов допускают частичную специализацию.

463035818_is_not_an_ai 19.06.2024 14:33

@463035818_is_not_an_ai теперь я понимаю. Обновлено соответственно.

wohlstad 19.06.2024 14:35
Ответ принят как подходящий

Для шаблонов функций не существует частичной специализации, но вы можете частично специализировать шаблон класса:

#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 19.06.2024 21:06

@LoS действительно, хотя для вопроса это не существенно. Спасибо, исправил

463035818_is_not_an_ai 20.06.2024 08:49

Другие вопросы по теме

Есть ли способ принудительно создать экземпляр функции-члена для каждого экземпляра шаблона?
Подсчитайте количество аргументов в общей лямбде
C++20 и новее – как лучше всего реализовать «перечисление с большей функциональностью»?
Возврат необязательного параметра из шаблонной функции преобразования
Достаточно ли предварительного объявления std::list, чтобы проверить, является ли тип T std::list?
Рекурсивный шаблон C++ с переменным числом вариантов
Ошибка компиляции при использовании функций шаблона C++, которые принимают в качестве аргументов другие функции, которые принимают ссылки на указатели
Специализация шаблона вне встроенного пространства имен функции, определенной внутри встроенного пространства имен
Как вывести в шаблон имя текущего тега? (Тот, в котором мы находимся)
Может ли быть нарушено ODR, если определение шаблона создается только с разными параметрами?