我需要在C ++中创建一个模板类。我需要确保template参数的类型将是具有1个int字段和1个字符串字段的类(可以有更多字段,但是这些是必填字段)。
例如,在C#中,我可以使用方法或属性定义一个接口,如下所示:
interface MyInterface {
int GetSomeInteger();
string GetSomeString();
}
然后我可以在模板类中使用它:
class MyClass<T> where T: MyInterface {}
在C ++中有什么方法可以做这样的事情吗?
答案 0 :(得分:3)
在当前版本的C ++中,最常见的实现方法是称为“鸭式打字”的技术。
它只涉及使用T
,就好像它实现了接口一样,如果您使用类型不兼容的类,则会让编译器失败。
template<typename T>
class MyClass<T> {
int foo() {
T val;
return val.GetSomeInteger();
}
};
class Valid {
public:
int GetSomeInteger() {return 0;}
};
class Invalid {
};
int main() {
// works fine
MyClass<Valid> a;
a.foo();
// fails to compile
MyClass<Invalid> b;
b.foo();
}
请介意,有一些方法可以更正式地执行此操作,但是所涉及的代码量通常并不值得。
答案 1 :(得分:2)
C ++ 20具有概念。一些编译器已经支持它们。例如,以下内容与gcc (trunk) -std=c++2a -fconcepts
:
#include <string>
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetIntAndString = requires(T& a) {
{ a.GetSomeInteger() } -> std::same_as<int>;
{ a.GetSomeString() } -> std::same_as<std::string>;
};
template <HasGetIntAndString T>
void bar(const T& t){
std::cout << t.GetSomeInteger() << " " << t.GetSomeString();
}
struct foo {
int GetSomeInteger() const { return 42; }
std::string GetSomeString() const { return "some"; }
};
struct foo_not {
std::string GetSomeInteger() { return "some"; }
int GetSomeString() { return 42; }
};
int main(){
bar( foo{});
bar( foo_not{});
}
导致:
<source>: In function 'int main()':
<source>:28:19: error: use of function 'void bar(const T&) [with T = foo_not]' with unsatisfied constraints
28 | bar( foo_not{});
| ^
<source>:12:6: note: declared here
12 | void bar(const T& t){
| ^~~
<source>:12:6: note: constraints not satisfied
<source>: In instantiation of 'void bar(const T&) [with T = foo_not]':
<source>:28:19: required from here
<source>:6:9: required for the satisfaction of 'HasGetIntAndString<T>' [with T = foo_not]
<source>:6:30: in requirements with 'T& a' [with T = foo_not]
<source>:7:23: note: 'a.GetSomeInteger()' does not satisfy return-type-requirement
7 | { a.GetSomeInteger() } -> std::same_as<int>;
| ~~~~~~~~~~~~~~~~^~
<source>:8:22: note: 'a.GetSomeString()' does not satisfy return-type-requirement
8 | { a.GetSomeString() } -> std::same_as<std::string>;
| ~~~~~~~~~~~~~~~^~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
在C ++ 20之前,您可以使用SFINAE。但是,将临时参数限制得不必要的情况通常更简单,更合适。如果模板确实调用了T::GetSomeInteger()
,但是类型T
没有这样的方法,则模板将无法进行编译而不采取任何进一步的措施。 SFINAE主要是提供更好的错误消息。