具有变异模板模板参数的方法的部分专业化

partial specialization of a method with variadic templated template parameter

本文关键字:专业化 方法 参数 变异      更新时间:2023-10-16

我有一个代码,该代码成功编译(G 4.9.2(:

#include <iostream>
#include <utility>
// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void
foo(T<TTs...>& arg)
{
    std::cout << "T<TTs...>" << std::endl;
}
template<typename ...Ts>
struct xxx
{
    // not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
foo(xxx<TTs...>& arg)
{
    std::cout << "xxx<TTs...>" << std::endl;
}
// specialization for non-variadic templated xxx
template<typename TT> void
foo(xxx<TT>& arg)
{
    std::cout << "xxx<TT>" << std::endl;
}
// specialization for xxx<uint8_t>
template<> void
foo(xxx<uint8_t>& arg)
{
    std::cout << "xxx<uint8_t>" << std::endl;
}
int
main(int argc, char** argv)
{
    xxx<uint8_t> x1;
    std::cout << "xxx<uint8_t> => ";
    foo(x1);
    xxx<uint16_t> x2;
    std::cout << "xxx<uint16_t> => ";
    foo(x2);
    xxx<uint8_t,uint16_t> x3;
    std::cout << "xxx<uint8_t,uint16_t> => ";
    foo(x3);
    std::pair<uint8_t,uint16_t> x4;
    std::cout << "std::pair<uint8_t,uint16_t> => ";
    foo(x4);
    return 0;
}

和生产:

xxx<uint8_t> => xxx<uint8_t>
xxx<uint16_t> => xxx<TT>
xxx<uint8_t,uint16_t> => xxx<TTs...>
std::pair<uint8_t,uint16_t> => T<TTs...>

现在我想在课堂内使用这些Foo方法,然后写:

#include <iostream>
#include <utility>
class abc
{
public:
    // general function for any variadic templated argument
    template<template<typename ...> class T, typename ...TTs>
    void
    foo(T<TTs...>& arg)
    {
        std::cout << "T<TTs...>" << std::endl;
    }
};
template<typename ...Ts>
struct xxx
{
    // not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
abc::foo(xxx<TTs...>& arg)
{
    std::cout << "xxx<TTs...>" << std::endl;
}
// specialization for non-variadic templated xxx
template<typename TT> void
abc::foo(xxx<TT>& arg)
{
    std::cout << "xxx<TT>" << std::endl;
}
// specialization for xxx<uint8_t>
template<> void
abc::foo(xxx<uint8_t>& arg)
{
    std::cout << "xxx<uint8_t>" << std::endl;
}
int
main(int argc, char** argv)
{
    abc p;
    xxx<uint8_t> x1;
    std::cout << "xxx<uint8_t> => ";
    p.foo(x1);
    xxx<uint16_t> x2;
    std::cout << "xxx<uint16_t> => ";
    p.foo(x2);
    xxx<uint8_t,uint16_t> x3;
    std::cout << "xxx<uint8_t,uint16_t> => ";
    p.foo(x3);
    std::pair<uint8_t,uint16_t> x4;
    std::cout << "std::pair<uint8_t,uint16_t> => ";
    p.foo(x4);
    return 0;
}

这会产生汇编错误:

test_ko.cc:24:1: error: prototype for ‘void abc::foo(xxx<TTs ...>&)’ does not match any in class ‘abc’
 abc::foo(xxx<TTs...>& arg)
 ^
test_ko.cc:10:5: error: candidate is: template<template<class ...> class T, class ... TTs> void abc::foo(T<TTs ...>&)
     foo(T<TTs...>& arg)
     ^
test_ko.cc:31:1: error: prototype for ‘void abc::foo(xxx<TT>&)’ does not match any in class ‘abc’
 abc::foo(xxx<TT>& arg)
 ^
test_ko.cc:10:5: error: candidate is: template<template<class ...> class T, class ... TTs> void abc::foo(T<TTs ...>&)
     foo(T<TTs...>& arg)

我想要Foo方法的专业化,而不是在ABC类中声明新的签名(因为有一个带有模板的类,库的一部分和单独的专业化,以后声明为XXX类(。

看来,带有方法的代码类似于具有功能的代码,但是我在这里遇到了错误。我做错了什么?

// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void
foo(T<TTs...>& arg)
{
  std::cout << "T<TTs...>" << std::endl;
}

这是一个模板函数。

template<typename ...Ts>
struct xxx
{
  // not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
foo(xxx<TTs...>& arg)
{
  std::cout << "xxx<TTs...>" << std::endl;
}

这是不是专业化。这是一个不同的模板函数,其名称foo与上述模板函数重载。

// specialization for non-variadic templated xxx
template<typename TT> void
foo(xxx<TT>& arg)
{
  std::cout << "xxx<TT>" << std::endl;
}

这是不是专业化。这是一个不同的模板函数,其名称foo与上述模板函数过载。

// specialization for xxx<uint8_t>
template<> void
foo(xxx<uint8_t>& arg)
{
  std::cout << "xxx<uint8_t>" << std::endl;
}

这是上述模板函数之一的完整专业化。我认为第三个,但我不会押注钱。(我相信,如果您打电话给foo,则专门针对哪种模板xxx<uint8_t>&(。

而不是这个完整的专业化,我会写:

inline foo(xxx<uint8_t>& arg)
{
  std::cout << "xxx<uint8_t>" << std::endl;
}

这再次是foo的全新超载。超负荷远不及完整功能专业的古怪。

没有部分模板函数propece

这解释了为什么您尝试使用相同语法专业的方法不起作用。没有诸如部分模板成员函数专业之类的东西。

您要么必须在类本身中写入过载,要么派遣到其他上下文。

什么"出了问题",是错误的直接原因是您的初始代码引入了 new Overloads 。您不允许在类定义之外引入新方法的新过载,因此编译器指出了您的错误。


这是一种有用的技术。我们在abc中:

// general function for any variadic templated argument
  template<template<typename ...> class T, typename ...TTs>
  void foo(T<TTs...>& arg)
  {
    return foo(*this, arg);
  }
private:
  template<template<typename ...> class T, typename ...TTs>
  friend void foo(abc& self, T<TTs...>& arg)
  {
    std::cout << "T<TTs...>" << std::endl;
  }

我们的foo方法扩展到foo朋友。

然后,我们在与abc相同的名称空间中添加代码:

template<typename ...TTs> void
foo(abc& self, xxx<TTs...>& arg)
{
  std::cout << "xxx<TTs...>" << std::endl;
}
template<typename TT> void
foo(abc& self, xxx<TT>& arg)
{
  std::cout << "xxx<TT>" << std::endl;
}
inline void foo(abc& self, xxx<uint8_t>& arg)
{
  std::cout << "xxx<uint8_t>" << std::endl;
}

,当abc::foo称为时,它们是通过ADL找到的。