簡體   English   中英

C++ 中的 C# 中是否有關鍵字“where”的類似物?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM