2016-09-25 47 views
3

期望的行为可以说明如下:是否可以使用元组中传递的所有可能的K组合(带重复)来调用方法?

void foo(int x, int y) { 
    std::cout << x << " " << y << std::endl; 
} 

int main() { 
    all_combinations<2>(foo, std::make_tuple(1, 2)); // K = 2 
    // to run: 
    // foo(1, 1) 
    // foo(1, 2) 
    // foo(2, 1) 
    // foo(2, 2) 
} 
+2

你只想要模板编程的答案?如果没有,我认为std :: next_permutation {1,1,2,2}可能会有所帮助。 –

+0

@KenmanTsang我没有想过运行时的方法,但它看起来很有前途...... –

+0

@ W.K。是的,编译时间的方法是最好的!但运行时方法可能是您的最终解决方案出来之前的解决方案 –

回答

1

C++的14版可以看看如下:

#include <tuple> 
#include <utility> 
#include <iostream> 
#include <initializer_list> 


template <class Foo, class Tuple, size_t... Is, size_t... Is2> 
int all_combinations_impl(Foo foo, Tuple t, std::index_sequence<Is...> , std::integral_constant<size_t, 0>, std::index_sequence<Is2...>) { 
    foo(std::get<Is>(t)...); 
    std::cout << std::endl; 
    return 0; 
} 

template <class Foo, class Tuple, size_t... Is, size_t K, size_t... Is2> 
int all_combinations_impl(Foo foo, Tuple t, std::index_sequence<Is...>, std::integral_constant<size_t, K>, std::index_sequence<Is2...> is) { 
    std::initializer_list<int> all = {all_combinations_impl(foo, t, std::index_sequence<Is..., Is2>{}, std::integral_constant<size_t, K-1>{}, is)...}; 
    (void)all; 
} 

template <size_t K, class Foo, class Tuple> 
void all_combinations(Foo foo, Tuple t) { 
    all_combinations_impl(foo, t, std::index_sequence<>{}, std::integral_constant<size_t, K>{}, std::make_index_sequence<std::tuple_size<Tuple>::value>{}); 
} 

int main() { 
    all_combinations<2>([](auto... args) { std::forward_as_tuple((std::cout << args)...); }, std::make_tuple("1 ", "2 ", "3 ")); 
} 

不幸的是C++ 11没有附带std::integer_sequence,所以我们需要做额外的实施:

#include <tuple> 
#include <utility> 
#include <iostream> 
#include <initializer_list> 

template <class T, T... Vs> 
struct integer_sequence { }; 

template <class T, class, class, class = integer_sequence<T>, class = integer_sequence<T, 0>, class = void> 
struct make_integer_sequence_impl; 

template <class T, T ICV1, T... Res, T... Pow> 
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 0>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, typename std::enable_if<(ICV1 > 0)>::type>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Res...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { }; 

template <class T, T ICV1, T... Res, T... Pow> 
struct make_integer_sequence_impl<T, std::integral_constant<T, ICV1>, std::integral_constant<T, 1>, integer_sequence<T, Res...>, integer_sequence<T, Pow...>, void>: make_integer_sequence_impl<T, std::integral_constant<T, ICV1/2>, std::integral_constant<T, ICV1%2>, integer_sequence<T, Pow..., (Res + sizeof...(Pow))...>, integer_sequence<T, Pow..., (Pow + sizeof...(Pow))...>> { }; 

template <class T, class Res, class Pow> 
struct make_integer_sequence_impl<T, std::integral_constant<T, 0>, std::integral_constant<T, 0>, Res, Pow, void> { 
    using type = Res; 
}; 

template <class T, T V> 
using make_integer_sequence = typename make_integer_sequence_impl<T, std::integral_constant<T, V/2>, std::integral_constant<T, V%2>>::type; 

template <size_t V> 
using make_index_sequence = make_integer_sequence<size_t, V>; 

template <size_t... V> 
using index_sequence = integer_sequence<size_t, V...>; 

template <class Foo, class Tuple, size_t... Is, size_t... Is2> 
int all_combinations_impl(Foo foo, Tuple t, index_sequence<Is...> , std::integral_constant<size_t, 0>, index_sequence<Is2...>) { 
    foo(std::get<Is>(t)...); 
    std::cout << std::endl; 
    return 0; 
} 

template <class Foo, class Tuple, size_t... Is, size_t K, size_t... Is2> 
int all_combinations_impl(Foo foo, Tuple t, index_sequence<Is...>, std::integral_constant<size_t, K>, index_sequence<Is2...> is) { 
    std::initializer_list<int> all = {all_combinations_impl(foo, t, index_sequence<Is..., Is2>{}, std::integral_constant<size_t, K-1>{}, is)...}; 
    (void)all; 
} 

template <size_t K, class Foo, class Tuple> 
void all_combinations(Foo foo, Tuple t) { 
    all_combinations_impl(foo, t, index_sequence<>{}, std::integral_constant<size_t, K>{}, make_index_sequence<std::tuple_size<Tuple>::value>{}); 
} 

struct s { 
    template <class... Args> 
    void operator()(Args... args) const { 
     std::forward_as_tuple((std::cout << args)...); 
    } 
}; 

int main() { 
    all_combinations<3>(s{}, std::make_tuple("1 ", "2 ", "3 ")); 
} 
+1

使用元组大小推断'K'?用'integral_constant'替换总是有一个元素的序列? – Yakk

+1

实际上'K'不能从元组大小推导出来,因为即使对于元组 {1,2} K可以是3来调用:'foo(1,1,1)','foo(1,1,2) ',... –

+0

虽然你是正确的与integral_constant! –

相关问题