2016-11-07 32 views
1

這是我試圖實現的簡化示例。因此,它可能看起來有點傻,但忍受着我。比方說,我有C++:如果條件不滿足,函數調用編譯時錯誤?

template<int i> 
class Class1{ 
foo(){cout<<"j is divisible by i, so we will hang out"<<endl;} 
} 

,並具有固定int j變量class2:要麼通過這樣一個int或有一個成員變量模板化。我想class2情況下只能夠調用foo()如果滿足一定條件,在這種情況下,我要確保說(j%i==0)

我能想出它的最好的是:

template<int i> 
class Class1{ 
    static const int intParam=i; 
    template<bool true> 
    foo(){cout<<"j is divisible by i, so we will hang out"<<endl;} 
} 

,然後2級會這樣稱呼它:

foo<class1::intParam%j>() 

這是不是很漂亮。有沒有更好的方法來做到這一點?我看到'std::enable_if'這是相關的,但我不太確定。

如果你想要更大的畫面,這是一個信號/委託中介機構。在一個系統中,任務對象應該能夠送達/由表演者要求,只有當他們匹配在任務中指定的角色枚舉(int i)對象。基本上這應該是沒有動態多態性的基於枚舉的設計。在C++中有更好的方法嗎?

+1

你嘗試過'static_assert'嗎? – krzaq

+0

@krzaq看到我對建議答案的評論。 – ShS

回答

4

使用static_assert

template<int i, int j> 
class Class1 
{ 
    public: 
    void foo() 
    { 
    static_assert(i % j == 0, "Message upon i % j == 0 being false"); 
    cout<<"j is divisible by i, so we will hang out"<<endl; 
    } 
}; 

而且例如叫它

Class1<42, 24> f; 
f.foo(); 

更新評論,只是添加j作爲一個額外的模板參數爲foo()則:

template<int i> 
class Class1 
{ 
    public: 
    template<int j> 
    void foo() 
    { 
    static_assert(i % j == 0, "Message upon i % j == 0 being false"); 
    cout<<"j is divisible by i, so we will hang out"<<endl; 
    } 
}; 

int main() 
{ 
    Class1<42> f; 
    f.foo<24>(); 
    return 0; 
} 
+0

謝謝。但是這會給我在foo()體內的錯誤,並且直到實際觸及編譯之前我都不會觸及它。我希望能阻止我在編輯器中寫foo()開始。 – ShS

+0

您的示例也偏離了上述示例。 j不屬於Class1。 – ShS

+4

@ user4376555這沒有多大意義。如果我在記事本中進行編程怎麼辦?直到我真正用代碼編譯我的文件之前,沒有什麼會被認爲是錯誤的。在編譯它之前,文本沒有任何意義。 –

1

編輯

你真正要求的是使寫作該代碼是一個錯誤,我很難過說這不是真的可能。我不認爲那裏有一個IDE可以防止你編寫無效的代碼。但是,如果您在下面實現了一個解決方案(編譯時),那麼一個足夠先進的IDE將能夠向您提供有關在編譯之前編寫的代碼很糟糕的信息。

像Visual Studio編譯器基本上將「編譯」你的東西在後臺,然後強調糟糕的代碼(讀:不會編譯)用紅色波浪線。

下面

您認爲一對夫婦爲您Class2結構的可能性,所以,讓我們將每個

編譯時檢查答案:

首先,我們將與您Class1開始基本上你定義它:

template<int i> 
struct Class1{ 
// how to define a "foo" function that is only callable 
// if Class2's j is evenly divisble by i? 
}; 

你的第一個可能性是Class2有一個模板化j參數:

template<int j> 
struct Class2 
{ 
    //... 
}; 

很好的解決,這將是對模板Class1foo方法,然後包括static_assert,這是一個編譯時斷言。這是可行的,因爲編譯時已知ij

現在Class1看起來是這樣的:

template<int i> 
struct Class1{ 
    template<int j> 
    void foo() 
    { 
     static_assert(j%i==0, "j is not evenly divisible by i"); 
     std::cout << "j is evenly divisble by i" << std::endl; 
    } 
}; 

而且Class2可以撥打foo這樣的:

template<int j> 
struct Class2 
{ 
    void CallFoo() 
    { 
     Class1<2> c1; 
     c1.foo<j>(); // works 

     //Class1<3> c2; 
     //c2.foo<2>(); // fails static assert 
    } 
}; 

Demo

你提到的另一種可能性是,Class2可以有一個成員變量爲j。你可以做到這一點,只要該成員變量是constexpr(也static結果):

struct Class2 
{ 
    static constexpr int j = 4; 
    void CallFoo() 
    { 
     Class1<2> c1; 
     c1.foo<j>(); // works 

     //Class1<3> c2; 
     //c2.foo<2>(); // fails static assert 
    } 
}; 

constexpr定義編譯時常在這裏。所以保證在編譯時知道這個值,我們的static_assert就可以工作。

如果j不是constexpr那麼我們不能實現我們的編譯時斷言。在這一點上你退居運行時異常處理:

template<int i> 
struct Class1{ 
    void foo(int j) 
    { 
     if (j%i != 0) 
      throw std::invalid_argument("j is not evenly divisible by i"); 
     std::cout << "j is evenly divisble by i" << std::endl; 
    } 
}; 

struct Class2 
{ 
    int j = 4; 
    void CallFoo() 
    { 
     Class1<2> c1; 
     c1.foo(j); // works 
     j = 3; 
     c1.foo(j); // throws 
    } 
}; 

Demo

+0

謝謝。爲了您的信息,這是我試圖去的方向︰https://github.com/ShahOdin/Broker/我創建了一個代理類來從基類映射中獲取模板類的技巧。想知道我能夠擴展這種基於枚舉的方法。 – ShS

2

由於相對於其他的解決方案,我推薦使用SFINAE以便能夠根據條件禁用功能。

template<int i> 
struct Class1 { 
    template<int j, std::enable_if_t<i % j == 0>* = 0> 
    void foo() { 

    } 
}; 

這個方案的好處是,如果有其他重載foo(),編譯器將嘗試它們,而不是給一個硬錯誤。正如你可以在這個Live Example看到,由編譯器給出的錯誤是:

main.cpp: In function 'int main()': 
main.cpp:12:24: error: no matching function for call to 'Class1<3>::foo()' 
    Class1<3>{}.foo<2>(); 
        ^

這意味着,在用戶代碼中出現錯誤,而不是在你的頭,那如果有另一種功能時,該一個沒有工作,編譯器會嘗試其他重載。

+0

謝謝!有沒有辦法與enable_if和不enable_if_t? – ShS

+1

是的。您可以使用'類型名稱的std :: enable_if <...> :: type',也可以使用enable_if_t =類型名enable_if ::類型定義自己的別名'模板<布爾B,類型名T =無效>;'。我推薦別名,因爲它使一切更具可讀性。 –