分别为数据成员和成员函数专门化模板
我想专门使用一个模板来对指向数据成员的指针做一件事,对指向成员函数的指针做另一件事。这曾经在 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)>>;
演示