分别为数据成员和成员函数专门化模板

我想专门使用一个模板来对指向数据成员的指针做一件事,对指向成员函数的指针做另一件事。这曾经在 gcc 11 之前一直有效,成员函数更具体。它仍然适用于 clang 11,但似乎与 gcc 中断了。

这是一个最小的非工作示例:

#include <iostream>

template<auto F> struct which;

template<typename K, typename V, K V::*F>
struct which<F> {
  static constexpr char desc[] = "pointer to data member";
};

template<typename K, typename V, K (V::*F)()>
struct which<F> {
  static constexpr char desc[] = "pointer to member function";
};

struct S {
  int i;
  int f() { return 0; }
};

int
main()
{
  std::cout << "S::i: " << which<&S::i>::desc << std::endl;
  std::cout << "S::f: " << which<&S::f>::desc << std::endl;
}

从 gcc 11.1 开始,编译g++ -std=c++17 memptr.cc给出:

memptr.cc: In function 'int main()':
memptr.cc:24:40: error: ambiguous template instantiation for 'struct which<&S::f>'
   24 |   std::cout << "S::f: " << which<&S::f>::desc << std::endl;
      |                                        ^~
memptr.cc:6:8: note: candidates are: 'template<class K, class V, K V::* F> struct which<F> [with K = int(); V = S; K V::* F = &S::f]'
    6 | struct which<F> {
      |        ^~~~~~~~
memptr.cc:11:8: note:                 'template<class K, class V, K (V::* F)()> struct which<F> [with K = int; V = S; K (V::* F)() = &S::f]'
   11 | struct which<F> {
      |        ^~~~~~~~
memptr.cc:24:42: error: incomplete type 'which<&S::f>' used in nested name specifier
   24 |   std::cout << "S::f: " << which<&S::f>::desc << std::endl;
      |                                          ^~~~

这是 gcc 中的错误,还是我的代码中的错误?无论哪种方式,最简单的解决方法是什么?

回答

我不确定,但我怀疑这是 GCC 错误。作为一种变通方法,您可以通过编写的签名有点修改代码F参数列表的专业化,而不是的参数列表,并推导一个类型,而不是一个非类型

template<typename F> struct which;

template<typename K, typename V>
struct which<K V::*> {
  static constexpr char desc[] = "pointer to data member";
};

template<typename K, typename V>
struct which<K (V::*)()> {
  static constexpr char desc[] = "pointer to member function";
};

要使用它,您需要编写,which<decltype(&S::i)>::desc因为需要一个类型。

演示


如果您希望将实际指针传递给专门化而不是类型,您还可以通过让现有类型特征完成工作来执行以下操作

// implementation
template<auto, bool> struct which_impl;

template<auto F>
struct which_impl<F, true> {
  static constexpr char desc[] = "pointer to data member";
};

template<auto F>
struct which_impl<F, false> {
  static constexpr char desc[] = "pointer to member function";
};

// helper alias
template<auto F> 
using which = which_impl<F, std::is_member_object_pointer_v<decltype(F)>>;

演示


以上是分别为数据成员和成员函数专门化模板的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>