检查子类型时的专用方法模板

Specializing method template while checking for subtype

本文关键字:方法 专用 类型 检查      更新时间:2023-10-16

在检查是否存在某些子类型的同时,为方法专用化模板的语法是什么?

// Syntax works fine for functions
template<class T, class... Assertions> void my_function();
template <class list_t, class list_t::value_type>
void my_function() { }
// Doesn't work for methods
class MyClass {
template<class T, class... Assertions> void my_method();
};
// Commenting out the next two lines results in successful compile
template <class list_t, class list_t::value_type>
void MyClass::my_method() { }
int main() { }

叮当给我:

out-of-line definition of 'my_method' does not match any declaration in 'MyClass'

您在这里既不专门介绍模板方法,也不专门介绍函数。您只是重载免费模板函数并尝试以奇怪的方式重载该方法。要使其正常工作,您应该使用标记调度(因为部分函数模板专用化在C++中是不可能的(或constexpr if如果您的编译器支持 C++17

专用化语法如下:

// dummy list_t...
struct list_t
{
using value_type = int;
};
// standard implementation:
template<class T, class... Assertions>
void my_function() { }
// specialization
template <>
void my_function<list_t, list_t::value_type>() { }
class MyClass
{
template<class T, class... Assertions>
void my_method();
};
// standard implementation:
template<class T, class... Assertions>
void MyClass::my_method() { }
// specialisation
template <>
void MyClass::my_method<list_t, list_t::value_type>() { }

我不清楚你到底想要什么。

如果您希望仅在T是类/结构且其中value_type类型时才实现该my_method(),并且您希望在使用没有value_typeT调用时出现编译错误,我建议通过declval()decltype()使用 SFINAE

。作为

template <typename T>
auto my_method ()
-> decltype( std::declval<typename T::value_type>(), void() )
{ }

如果可以使用 C++17 代替decltype( std::declval<typename T::value_type>(), void() ),则可以使用std::void_t<T::value_type>

如果你想要一个具有更通用版本和带有value_type的类/结构的专用版本的my_method(),我建议开发一个泛型my_method(),只需调用另一个方法my_method_helper()添加一个int

template <typename T>
void my_method ()
{ my_method_helper<T>(0); }

并将 SFINAE 和函数重my_method_helper()载与接收long(因此不完全是int(的my_method_helper()相结合,并为更通用的版本启用

template <typename T>
void my_method_helper (long)
{ }

以及完全接收int的版本(因此最好在可用时优于long版本(,但仅在T包含value_type时才启用。

template <typename T>
auto my_method_helper (int)
-> decltype( std::declval<typename T::value_type>(), void() )
{ }

因此,当T包含value_type时调用my_method_helper(int),否则调用my_method_helper(long)

下面是一个完整的编译示例(方法名称已更改(

#include <utility>
#include <iostream>
struct MyClass
{
template <typename T>
auto method_1 ()
-> decltype( std::declval<typename T::value_type>(), void() )
{ std::cout << "method_1 " << std::endl; }
template <typename T>
auto method_2 (int)
-> decltype( std::declval<typename T::value_type>(), void() )
{ std::cout << "method_2 specialized" << std::endl; }
template <typename T>
void method_2 (long)
{ std::cout << "method_2 generic" << std::endl; }
template <typename T>
void method_2 ()
{ method_2<T>(0); }
};
struct foo
{ using value_type = int; };
int main()
{
MyClass mc;
mc.method_1<foo>();
// mc.method_1<int>(); // compilation error
mc.method_2<foo>(); // call specialized version
mc.method_2<int>(); // call generic version
}

部分题外话:我不明白"语法适用于函数"是什么意思

template<class T, class... Assertions> void my_function();
template <class list_t, class list_t::value_type>
void my_function() { }

你怎么称呼my_function()