2017-12-18 62 views
18

我有一個類與接受的整數的模板來確定的參數的固定量:功能的一個整數

template <unsigned int N> 
class Example {}; 

我在尋找一種方法來定義一個(部件)函數接受一些數量爲Example對象作爲參數。量是由N來決定,因此功能會像這樣使用:

Function(Example<2>(), Example<2>()); 
Function(Example<3>(), Example<3>(), Example<3>()); 

我試了一下,到目前爲止:

使用的初始化列表,一個是能夠通過一組對象的功能:

template <unsigned int N> 
void Function(std::initializer_list<Example<N>> list); 
//... 
Function({Example<2>(), Example<2>()}); 

然而,除了那真的只有一個參數傳遞(列表)的事實,問題是,這種方法可以使用任意數量的參數:

Function({Example<2>()}); 

我使用可變參數函數也試過:

template <unsigned int N> 
void Function(Example<N> e...) 
{ 
    va_list args; 
    va_start(args, e); 
    //... 
} 
Function(Example<2>(), Example<2>()); 

這使得可以使用真正的參數,但使用任意數量的參數的問題仍然存在,而這是不可能知道有多少爭論實際上已通過。

+0

,補充維托裏奧·羅密歐的回答是:https://stackoverflow.com/questions/39659127/restrict-variadic-template-arguments – bolov

回答

21

假設你想要的參數從Example<N>類型推斷的數量,並且所有Example<I>應該共享相同的這種N,一個C++ 17的解決方案可能是

template <unsigned int... I> 
auto Function(Example<I>...) -> 
    std::enable_if_t<((I == sizeof...(I)) && ...)> 
{ 
    // or static_assert() if you always want an error 
} 
+0

你能檢查我的答案嗎?我認爲它可以在C++ 11/C++ 14中完成。 –

+1

@ Sergey.quixoticaxis.Ivanov確信它可以,但是一個簡單的,遞歸定義的類型特徵會在這種情況下做到;專業化就像*「struct AreSameExamples :std :: conditional ,std :: false_type> :: type {};」* ... –

+0

對不起,我是新來編寫模板或至少嚴重模板化)的代碼。你的意思是檢查所有參數是否與你描述的模板具有相同的「S 」專業化更容易? –

5

Function一個可變參數模板和使用std::enable_if_t來約束你的吧:

  • 一些IsExample特性可用於確保所有參數都是Example

  • sizeof...(pack)可實例用於獲取參數包的大小

template <unsigned int N, typename... Ts> 
auto Function(Ts... xs) 
    -> std::enable_if_t<(IsExample<Ts>::value && ...) 
        && (sizeof...(Ts) == N)> 
{ 
} 

live example on wandbox

+1

如果我正確讀取的問題,OP想要N到被推斷並且不想要「功能(示例<0> {},示例<1> {});」以匹配... –

5

您應該在static_assert中使用可變參數函數模板。與涉及enable_if的方法不同,如果傳遞了不正確的參數,則此方法將產生一個可讀的錯誤消息。

template<unsigned int ... I> 
void Function(Example<I>... items) 
{ 
    static_assert 
    (
     true && (... && (static_cast<unsigned int>(sizeof...(I)) == I)) 
    , "This function accepts N arguments of type Example<N>" 
    ); 
} 

Online compiler

+0

static_assert的顯式錯誤消息的確有幫助。 – YSC

+1

你不需要'true &&'部分。 '... && x'爲空包是'true'。 – Barry

+0

@Barry Plus它是在完全錯誤的地方,如果它是爲了處理空包的情況... –

0

+1爲的Massimiliano簡氏優雅的解決方案。

不幸的是使用摺疊因此只適用於C++ 17。

爲了測試,用C++ 11/C++ 14,即所有I是等於sizeof...(I)(這也許sizeof...(I)等於N,其中N是類模板參數),這是足夠的測試,一個可變參數類型,它接收無符號值,是具有不同值的順序的相同類型。

我的意思是:宣佈一個微不足道的結構作爲

template <std::size_t ... Is> 
struct IList; 

測試可以

std::is_same<IList<N, sizeof...(Is), Is...>, 
      IList<sizeof...(Is), Is..., N>>::value 

從C++ 14有可能開始使用std::index_sequence而不是IList

所以Example可以寫成

template <unsigned int N> 
struct Example 
{ 
    template <unsigned int ... Is> 
    auto Function (Example<Is> ...) 
     -> typename std::enable_if< 
      std::is_same<IList<N, sizeof...(Is), Is...>, 
         IList<sizeof...(Is), Is..., N>>::value>::type 
    { /* do something */ } 
}; 

下面是使用的例子(但要記住,<type_traits>

int main() 
{ 
    Example<1U> e1; 
    Example<2U> e2; 

    // e1.Function(); // error 
    e1.Function(Example<1>{}); // compile 
    //e1.Function(Example<1>{}, Example<1>{}); // error 

    // e2.Function(); // error 
    //e2.Function(Example<2>{}); // error 
    e2.Function(Example<2>{}, Example<2>{}); // compile 
    //e2.Function(Example<2>{}, Example<2>{}, Example<2>{}); // error 
} 
2

有覆蓋SFINAE友好的基於約束的很多答案,但我不喜歡把我的SFINAE放在返回值中:

template <unsigned int... Is, 
    std::enable_if_t<((Is == sizeof...(Is)) && ...), bool> = true 
> 
void Function(Example<Is>... examples) 
{ 
    // code 
} 

template<bool b> 
using test_requirement = std::enable_if_t<b, bool>; 

template <unsigned int... Is, 
    test_requirement<((Is == sizeof...(Is)) && ...)> = true 
> 
void Function(Example<Is>... examples) 
{ 
    // code 
} 
可能感興趣的
+0

我花了一個多小時瞭解這=)當你的編譯器不支持你的功能時,重新嘗試潛入。 –

+0

@ Sergey.quixoticaxis.Ivanov在一些編譯器上,'class = test_requirement < blah >'有效,但上面沒有;然而,上面有更好的重載分辨率屬性,所以我更喜歡它。 – Yakk

+0

Ty爲信息。不幸的是,VS2017中的msvc似乎認爲將'...'摺疊爲語法錯誤。 –