用于检查友元函数是否存在的 C++ 模板
C++ template to check existence of friend function
我正在努力使以下代码正常工作。这会打印出“No setAttr”,感觉出乎意料。
基本上我在 Parent class 中有一个方法,它创建子 class 的实例并检查给定类型是否具有特定方法。这在我创建方法 (setAttr()) public 但不适用于友元函数时有效。
我知道这可能看起来有点奇怪,使用一些遗留代码,我试图解决它的用例以隐藏特定方法 (setAttr()) 一旦创建,这应该只能访问来自基础 class,它将负责生成子 classes
的实例
template <typename, typename = void_t<>>
struct has_set_attr_method {
static constexpr bool value = false;
};
template <typename T>
struct has_set_attr_method<T, void_t<decltype(std::declval<T>().setAttr())>> {
static constexpr bool value = true;
};
struct Parent {
public:
template<typename T>
static void create() {
auto obj = T::create();
if constexpr(has_set_attr_method<T>::value) {
cout << "has setAttr" << endl;
obj.toString();
} else {
cout << "no setAttr" << endl;
}
}
};
struct Child : public Parent {
public:
friend class Parent;
static auto create() {
return Child();
}
private:
void setAttr(int x) {
}
};
int main(int argc, char const *argv[]) {
Parent::create<Child>();
return 0;
}
你的代码有一些错误:
首先,您正在检查没有参数的方法,但您想要检查 void setAttr(int x)
。如果你想用 int
检查方法,你的测试必须是这样的:decltype(std::declval<T>().setAttr(1)
(在这里查看额外的 int 参数!)
如果你这样做,我们 运行 在一个 gcc 错误!它抱怨在模板声明中调用私有函数。由于 SFINAE 的确切意思是如果我们在模板声明中出现错误,我们不想引发错误,我相信这是一个 gcc 错误。 clang 编译没有任何问题。
顺便说一句:这里已经讨论过这个错误:
Private member access in template substitution and SFINAE and here: https://code-examples.net/en/q/25ea9ff
现在也作为错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96204
OK,但结果还是永久return false
.
为什么:
我们只是在当前类型的上下文中检查,所以 friend
没有效果!
解决方案:在正确的上下文中进行检查!只需将检查模板放在当前 class.
的上下文中
如此完整的代码示例(仅使用 clang,因为 gcc 抱怨模板声明中的 private 感觉不对!)
struct Parent {
template <typename, typename = void_t<>>
struct has_set_attr_method {
static constexpr bool value = false;
};
template <typename T>
struct has_set_attr_method<T, void_t<decltype(std::declval<T>().setAttr(1))>> {
static constexpr bool value = true;
};
public:
template<typename T>
static void create() {
auto obj = T::create();
if constexpr(has_set_attr_method<T>::value) {
cout << "has setAttr" << endl;
} else {
cout << "no setAttr" << endl;
}
}
};
struct Child : public Parent {
public:
//friend class Parent;
static auto create() {
return Child();
}
private:
void setAttr(int x) {
}
};
int main(int argc, char const *argv[]) {
Parent::create<Child>();
return 0;
}
我正在努力使以下代码正常工作。这会打印出“No setAttr”,感觉出乎意料。
基本上我在 Parent class 中有一个方法,它创建子 class 的实例并检查给定类型是否具有特定方法。这在我创建方法 (setAttr()) public 但不适用于友元函数时有效。
我知道这可能看起来有点奇怪,使用一些遗留代码,我试图解决它的用例以隐藏特定方法 (setAttr()) 一旦创建,这应该只能访问来自基础 class,它将负责生成子 classes
的实例template <typename, typename = void_t<>>
struct has_set_attr_method {
static constexpr bool value = false;
};
template <typename T>
struct has_set_attr_method<T, void_t<decltype(std::declval<T>().setAttr())>> {
static constexpr bool value = true;
};
struct Parent {
public:
template<typename T>
static void create() {
auto obj = T::create();
if constexpr(has_set_attr_method<T>::value) {
cout << "has setAttr" << endl;
obj.toString();
} else {
cout << "no setAttr" << endl;
}
}
};
struct Child : public Parent {
public:
friend class Parent;
static auto create() {
return Child();
}
private:
void setAttr(int x) {
}
};
int main(int argc, char const *argv[]) {
Parent::create<Child>();
return 0;
}
你的代码有一些错误:
首先,您正在检查没有参数的方法,但您想要检查 void setAttr(int x)
。如果你想用 int
检查方法,你的测试必须是这样的:decltype(std::declval<T>().setAttr(1)
(在这里查看额外的 int 参数!)
如果你这样做,我们 运行 在一个 gcc 错误!它抱怨在模板声明中调用私有函数。由于 SFINAE 的确切意思是如果我们在模板声明中出现错误,我们不想引发错误,我相信这是一个 gcc 错误。 clang 编译没有任何问题。
顺便说一句:这里已经讨论过这个错误: Private member access in template substitution and SFINAE and here: https://code-examples.net/en/q/25ea9ff
现在也作为错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96204
OK,但结果还是永久return false
.
为什么:
我们只是在当前类型的上下文中检查,所以 friend
没有效果!
解决方案:在正确的上下文中进行检查!只需将检查模板放在当前 class.
的上下文中如此完整的代码示例(仅使用 clang,因为 gcc 抱怨模板声明中的 private 感觉不对!)
struct Parent {
template <typename, typename = void_t<>>
struct has_set_attr_method {
static constexpr bool value = false;
};
template <typename T>
struct has_set_attr_method<T, void_t<decltype(std::declval<T>().setAttr(1))>> {
static constexpr bool value = true;
};
public:
template<typename T>
static void create() {
auto obj = T::create();
if constexpr(has_set_attr_method<T>::value) {
cout << "has setAttr" << endl;
} else {
cout << "no setAttr" << endl;
}
}
};
struct Child : public Parent {
public:
//friend class Parent;
static auto create() {
return Child();
}
private:
void setAttr(int x) {
}
};
int main(int argc, char const *argv[]) {
Parent::create<Child>();
return 0;
}