2015-06-06 38 views
3

我想仿效Python的in運算符在C + +(11),使用immedate值,你可以在Python中。如:一個C++的「in」運算符沒有cruft?

if x in (1, 2, 3): ... 

在C++ 11,看來我接近能夠做到這一點:

if (IsIn(x, { 1, 2, 3 })) 
    { 
    } 


template<typename Val, Container cont> 
bool IsIn(Val const &val, Container const &cont) 
    { 
    return boost::find(cont, val) != cont.end(); 
    } 

但(以g ++ - 4.8)我得到:

error: no matching function for call to 'IsIn(MyType&, <brace-enclosed initializer list>)'

我知道我能做到這一點,但是這是一個很大的克魯夫特:

if (IsIn(x, std::initializer_list<MyType>{1, 2, 3 })) ... 

什麼是優雅的解決方案?

更新:我對編譯時間和運行時間沒有足夠的瞭解,我仍然無法確定是否有明確的勝利者。我的IsIn(x, {})肯定會有更多的運行時循環開銷並複製initializer_list值,但也適用於任何容器。 ... == any_of(...機制肯定會編譯成更嚴格的代碼,並不複製,但只適用於立即數(這是我的原始示例),而不是容器,並且sytax(對我來說)似乎不太直截了當。

由於這是一種領帶,我將其授予貢獻者感謝。

感謝大家的討論!

+1

另一種方法,你可能會做類似的事情:http://coliru.stacked-crooked。com/a/3bcf0c0b56b47ce3 –

+1

你可以看看[named-operators-in-C++](http://codereview.stackexchange.com/questions/23179/named-operators-in-c)或https://github.com/klmr/named-operator用於* named-operator *能夠使用'if(x {1,2,3})'語法 – Jarod42

回答

1

我的道歉無恥的插件,但我認爲它解決了OP的問題。

您可以使用this library

#include "smart_conditions.hpp" 
using namespace smart_conditions; 

// ... 

if (x == any_of (1, 2, 3)) 
{ 
    // ... 
} 

它支持其他關係運算符,它的,如果所有的操作數是在編譯時已知的編譯時間constexpr)的作品,這讓無份。另外,它適用於混合類型,這意味着if (std::string("x") == any_of ("x", "y"))編譯好。

+0

與其他答案相比,這確實不會增加任何內容。 – Puppy

+0

那麼,如果你看看源代碼,我認爲它確實如此。這個想法不是使用initializer_list,也不是使用容器,也不使用任何類型的迭代器,而是利用元組和可變模板。我真的很抱歉,這聽起來像是自我推銷。即使你沒有檢查代碼,它也可以簡單而準確地完成OP所要求的很少或根本沒有的「cruft」。我相信你應該重新考慮;) – gd1

+0

OP顯然*希望*初始化列表和他*希望*容器。不使用它們使得事實上對他來說毫無用處。 – Puppy

3

溶液權在我的鼻子......

template<typename Val> 
bool IsIn(Val val, std::initializer_list<Val> const &cont) 
    { 
    return boost::find(cont, val) != cont.end(); // include <boost/range/algorithm.hpp> 
    // Or if you don't want boost, include <algorithm> 
    // return std::find(cont.begin(), cont.end(), val) != cont.end(); 
    } 
+0

作爲更一般的解決方案,我會創建兩個重載,所以您可以使用手工製作的初始化程序列表或在運行時填充的容器。 – petersohn

+0

'std :: find'不能代替'boost :: find'與g ++ -std = C++ 14 -O2 -Wall -pedantic。我也檢查過鐺 – Steephen

+0

你只是想知道'cont'是否出現在'cont'中,所以簡單地做'return std :: any_of(begin(cont),end(cont),Val)'。 – edmz

0

有2個的情況下,一個在那裏你可以打電話container.find(value)和其他地方調用std::find(container.begin(), container.end(), value)

template<typename IteratorType, typename Type> 
bool 
contains (IteratorType first, IteratorType last, Type const& value) 
{ 
    return std::find (first, last, value) != last; 
} 


template <template <typename, typename ...> class ContainerType, typename KeyType, typename... Types> 
bool 
contains_key 
    (ContainerType <KeyType, Types ...> const& container 
    , KeyType const& key 
    ) 
{ 
    return container.find (key) != container.end (); 
} 
2

另一個小想法:

template<typename T, typename ... Args> 
struct in_impl 
{ 
    in_impl(T const& t, Args const& ... args) : val({t, args ...}) {} 

    std::array<T, sizeof ...(Args) + 1> val; 
}; 


template<typename T, typename ... Args> 
bool operator==(T const& t, in_impl<T, Args ...> const& in) 
{ 
    return std::find(std::begin(in.val), std::end(in.val), t) != std::end(in.val); 
} 


template<typename T, typename ... Args> 
auto in(T const& t, Args const& ... args) 
{ 
    return in_impl<T, Args ...>(t, args ...); 
} 

這可以被用來作爲

int main() 
{ 
    if(1 == in(1,2,3)) 
    { 
     std::cout<<"1 is in"<<std::endl; 
    } 
} 

DEMO

多一點關懷,可以採取在得到領導型T,但這個想法應該變得清晰。

+0

做得很好,+1,但你正在製作我想要的副本。 – gd1

+0

我認爲這種方法也可以做成'constexpr'。 – davidhigh

+0

我認爲它*應*。如果你使用元組加上完美的轉發,你可以使用混合類型並避免複製。 – gd1