C++ c++;类型特征:确保子类实现方法
有一个虚拟的C类 我希望确保从C继承的任何具体子类都实现一个函数“get”(如果没有,则有一个明确的编译时错误) 在这种情况下,向C添加一个虚拟的“get”函数将不起作用,因为C子类可以实现各种签名的get函数 (在我正在研究的特定案例中,pybind11将用于创建子类的绑定,pybind11对B的“get”方法具有强大的健壮性,可以拥有广泛的签名) 在编译时检查一个类是否有函数可以通过类型特征来完成,例如C++ c++;类型特征:确保子类实现方法,c++,inheritance,typetraits,C++,Inheritance,Typetraits,有一个虚拟的C类 我希望确保从C继承的任何具体子类都实现一个函数“get”(如果没有,则有一个明确的编译时错误) 在这种情况下,向C添加一个虚拟的“get”函数将不起作用,因为C子类可以实现各种签名的get函数 (在我正在研究的特定案例中,pybind11将用于创建子类的绑定,pybind11对B的“get”方法具有强大的健壮性,可以拥有广泛的签名) 在编译时检查一个类是否有函数可以通过类型特征来完成,例如 模板 使用has_get= decltype(std::declval().get(st
模板
使用has_get=
decltype(std::declval().get(std::declval());
我的问题是,我应该在代码中的何处添加静态断言(或smthg else)来检查“get”函数的存在性。理想情况下,这应该是C声明的一部分,因为从它继承的新用户代码应该很容易。也可能是一种完全不同的方法会更好,我很想听听。不确定您使用的是什么标准,但使用C++20,您可以使用概念做类似的事情
template<typename T>
concept HasGet = requires (T a)
{
a.get();
};
template<HasGet T>
void foo(T x)
{
x.get();
}
struct Foo
{
int get() {
return 1;
}
};
struct Bar
{
};
int main()
{
foo(Foo{});
foo(Bar{});
}
模板
概念HasGet=requires(TA)
{
a、 get();
};
模板
void foo(T x)
{
x、 get();
}
结构Foo
{
int get(){
返回1;
}
};
结构条
{
};
int main()
{
foo(foo{});
foo(Bar{});
}
错误:
<source>: In function 'int main()':
<source>:27:12: error: use of function 'void foo(T) [with T = Bar]' with unsatisfied constraints
27 | foo(Bar{});
| ^
<source>:8:6: note: declared here
8 | void foo(T x)
| ^~~
<source>:8:6: note: constraints not satisfied
<source>: In instantiation of 'void foo(T) [with T = Bar]':
<source>:27:12: required from here
<source>:2:9: required for the satisfaction of 'HasGet<T>' [with T = Bar]
<source>:2:18: in requirements with 'T a' [with T = Bar]
<source>:4:9: note: the required expression 'a.get()' is invalid
4 | a.get();
:在函数“int main()”中:
:27:12:错误:使用函数“void foo(T)[with T=Bar]”时约束未得到满足
27 | foo(Bar{});
| ^
:8:6:注:此处声明
8 | void foo(T x)
| ^~~
:8:6:注意:未满足约束条件
:在“void foo(T)[T=Bar]的实例化中:
:27:12:从这里开始需要
:2:9:满足“HasGet”要求所需[T=Bar]
:2:18:in带“T a”的要求[带T=Bar]
:4:9:注意:所需的表达式“a.get()”无效
4 | a.获取();
编辑:
由于C++14是首选,如果我了解您的需求,这是您可以在C++14中执行的操作
#include <type_traits>
#include <utility>
using namespace std;
template<typename... Ts>
using void_t = void;
template<typename T, typename = void>
struct has_get
: false_type
{};
template<typename T>
struct has_get<T, void_t<decltype(declval<T>().get())>>
: true_type
{};
template<typename T>
static constexpr auto has_get_v = has_get<T>::value;
struct P
{
};
struct C1 : P
{
int get()
{
return 1;
}
};
struct C2 : P
{
float get()
{
return 1.0F;
}
};
struct C3
{
bool get()
{
return true;
}
};
template<typename T>
enable_if_t<is_base_of<P, decay_t<T>>::value && has_get_v<decay_t<T>>> foo(T x)
{
x.get();
}
int main()
{
foo(C1{});
foo(C2{});
foo(C3{});
}
#包括
#包括
使用名称空间std;
模板
使用void\u t=void;
模板
结构已经得到了
:false_类型
{};
模板
结构已经得到了
:true_类型
{};
模板
静态constexpr auto has_get_v=has_get::value;
结构P
{
};
结构C1:P
{
int get()
{
返回1;
}
};
结构C2:P
{
float get()
{
返回1.0F;
}
};
结构C3
{
boolget()
{
返回true;
}
};
模板
启用\u if\u t foo(t x)
{
x、 get();
}
int main()
{
foo(C1{});
foo(C2{});
foo(C3{});
}
错误:
<source>: In function 'int main()':
<source>:61:11: error: no matching function for call to 'foo(C3)'
61 | foo(C3{});
| ^
<source>:52:77: note: candidate: 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T)'
52 | enable_if_t<is_base_of<P, decay_t<T>>::value && has_get<decay_t<T>>::value> foo(T x)
| ^~~
<source>:52:77: note: template argument deduction/substitution failed:
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]':
<source>:52:77: required by substitution of 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T) [with T = C3]'
<source>:61:11: required from here
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:2554:11: error: no type named 'type' in 'struct std::enable_if<false, void>'
2554 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
:在函数“int main()”中:
:61:11:错误:对“foo(C3)”的调用没有匹配的函数
61 | foo(C3{});
| ^
:52:77:注意:候选:“模板标准::启用\u if\u t foo(t)”
52 |启用_if_t foo(t x)
| ^~~
:52:77:注意:模板参数扣除/替换失败:
包含在以下文件中:1:
/opt/compiler explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:替换“使用enable_if_t=typename std::enable_if::type[with bool _Cond=false;_Tp=void]的模板”:
:52:77:替换“模板std::enable_if_t foo(t)[with t=C3]时需要”
:61:11:从这里开始需要
/opt/compiler explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:2554:11:错误:在“struct std::enable_if”中没有名为“type”的类型
2554 |使用enable_if_t=typename enable_if::type;
Hm.纯虚拟函数怎么样?这应该可以。@ArminMontigny但使用哪个签名?理想情况下,我更喜欢c++14的解决方案,但这也是非常有用的。但是关于继承问题呢?thx对于更新来说太多了,确实是我需要的。我无法理解c++20版本。我说的对吗?它仍然要求用户在某个地方调用“foo”函数以确保编译时失败?是的,但根据代码的结构,您可以在其他地方使用enable_