[英]Is there an analogue of keyword “where” from C# in C++?
我需要在 C++ 中創建一個模板 class。 我需要確保模板參數的類型是 class 具有 1 個 int 字段和 1 個 string 字段(可以有更多字段,但這些是強制性的)。
例如,在 C# 中,我可以定義一個帶有方法或屬性的接口,如下所示:
interface MyInterface {
int GetSomeInteger();
string GetSomeString();
}
然后我可以在我的模板 class 中使用它:
class MyClass<T> where T: MyInterface {}
有沒有辦法在 C++ 中做這樣的事情?
C++20 為您提供最接近 C# 的解決方案:
#include <concepts>
template <class T>
concept MyInterface = requires(T x)
{
{ x.GetSomeInteger() } -> std::same_as<int>;
};
接着:
template <MyInterface T>
struct MyClass
{
// ...
};
在當前版本的 C++ 中執行此操作的最常見方法是一種稱為“duck-typing”的技術。
它只涉及使用T
,就好像它實現了接口一樣,如果使用不兼容類型的 class 則讓編譯器失敗。
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();
}
請注意,有一些方法可以更正式地執行此操作,但所涉及的代碼量通常不值得。
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 主要是為了提供更好的錯誤信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.