2017-03-17 89 views
1

我想使用boost::range::combine作爲笛卡兒的力量,而不僅僅是一個產品。boost :: range ::結合重複的參數

因此,而不是這樣的表達boost::range::combine(myRange, myRange, myRange);寫東西像myCombine(myRange, 3);

它是如何實現的?

回答

1

在C++ 17或C++ 14中實現這一點會更容易和更清晰,但由於您用標記了此處,因此這是一個兼容的實現。這裏有一種調用函數對象f的通用方法,它具有重複N次的相同參數。

首先,我們需要的結合通用函數對象f的第一個參數,然後接受任何數量的參數的方式:

template <typename TF, typename T> 
struct bound 
{ 
    TF _f; 
    T _x; 

    template <typename TFFwd, typename TFwd> 
    bound(TFFwd&& f, TFwd&& x) 
     : _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)} 
    { 
    } 

    template <typename... Ts> 
    auto operator()(Ts&&... xs) 
     -> decltype(_f(_x, std::forward<Ts>(xs)...)) 
    { 
     return _f(_x, std::forward<Ts>(xs)...); 
    } 
}; 

template <typename TF, typename T> 
auto bind_first(TF&& f, T&& x) 
    -> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x))) 
{ 
    return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)); 
} 

然後,我們需要一個遞歸helper將結合一個參數x多個TN時間:

template <std::size_t TN> 
struct helper 
{ 
    template <typename TF, typename T> 
    auto operator()(TF&& f, T&& x) 
     -> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x)) 
    { 
     return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x); 
    } 
}; 

template <> 
struct helper<0> 
{ 
    template <typename TF, typename T> 
    auto operator()(TF&& f, T&& x) 
     -> decltype(f(x)) 
    { 
     return f(x); 
    } 
}; 

最後,我們可以提供一個很好的界面:

template <std::size_t TN, typename TF, typename T> 
auto call_with_same_arg(TF&& f, T&& x) 
    -> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x))) 
{ 
    return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)); 
} 

用法:

int add(int a, int b, int c) 
{ 
    return a + b + c; 
} 

int main() 
{ 
    assert(call_with_same_arg<3>(add, 5) == 15); 
} 

live wandbox example


下面是一個完整的C++ 17的實現同樣的事情:

template <std::size_t TN, typename TF, typename T> 
decltype(auto) call_with_same_arg(TF&& f, T&& x) 
{ 
    if constexpr(TN == 1) 
    { 
     return f(x); 
    } 
    else 
    { 
     return call_with_same_arg<TN - 1>(
      [&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x); 
    } 
} 

live wandbox example


對於完整性,C++ 14的實現:

template <std::size_t TN> 
struct helper 
{ 
    template <typename TF, typename T> 
    decltype(auto) operator()(TF&& f, T&& x) 
    { 
     return helper<TN - 1>{}(
      [&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x); 
    } 
}; 

template <> 
struct helper<0> 
{ 
    template <typename TF, typename T> 
    decltype(auto) operator()(TF&& f, T&& x) 
    { 
     return f(x); 
    } 
}; 

template <std::size_t TN, typename TF, typename T> 
decltype(auto) call_with_same_arg(TF&& f, T&& x) 
{ 
    return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)); 
} 

live wandbox example

+0

謝謝你的答案。如果你考慮過其他C++標準的解決方案,可以在這裏寫出來。我只寫了C++ 11,以表明它可能(也是)模板元編程技巧。 –

+0

歐,你剛剛發佈了C++ 17版本。有沒有什麼與C++ 14相同的簡單解決方案的C + + 17? –

+0

@YaroslavKishchenko:它有點長,但比C++ 11更好。將在一秒後發佈。 –