在参数中强制执行的单一类型的C ++参数包

时间:2017-11-24 10:08:12

标签: c++ c++11 c++14 variadic-templates c++17

我希望能够做到以下几点:

save

以下答案并不令人满意:他们只想检查参数包是否属于单一类型,但我想在参数中将值正确转换为它(否则它不起作用)。 / p>

C++ parameter pack, constrained to have instances of a single type?

Parameter with non-deduced type after parameter pack

Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc?

我也不能使用initializer_list,因为我无法计算传递给#include <array> struct blah { }; template<typename... Args> constexpr auto foo(Args&&... args) { return std::array<blah, sizeof...(Args)>{{ args... }}; } auto res = foo({}, {}); 类型的参数数量。 而且我特别想要输入array

我有什么可能性?

3 个答案:

答案 0 :(得分:4)

lazies(C ++ 17)稍微扩展approach of Jarod42

#include <utility>
#include <array>

struct blah {};

template <class T, std::size_t I>
using typer = T;

template <class T, std::size_t N, class = std::make_index_sequence<N>>
struct bar_impl;

template <class T, std::size_t N, std::size_t... Is>
struct bar_impl<T, N, std::index_sequence<Is...>> {
    static auto foo(typer<T, Is>... ts) {
        return std::array<T, N>{{ts...}};
    }
};

template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;

template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar_impl<T, Is>... {
    using bar_impl<T, Is>::foo...;
};

int main() {
    bar<>::foo({}, {});
}

[live demo]

修改

某些C ++ 14解决方案(如max66所述)甚至比我预期的更简单:

#include <utility>
#include <array>

struct blah {};

template <class T, std::size_t I>
using typer = T;

template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;

template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
    using bar<T, N - 1>::foo;
    static auto foo(typer<T, Is>... ts) {
        return std::array<T, N>{{ts...}};
    }
};

template <class T>
struct bar<T, 0, std::index_sequence<>> {
    static auto foo() {
        return std::array<T, 0>{{}};
    }
};

int main() {
    bar<>::foo({}, {});
}

[live demo]

再修改一次:

这个(由Jarod42建议)提供与OP的问题完全相同的调用语法:

#include <utility>
#include <array>

struct blah {};

template <class T, std::size_t I>
using typer = T;

template <class T = blah, std::size_t N = 10, class = std::make_index_sequence<N>>
struct bar;

template <class T, std::size_t N, std::size_t... Is>
struct bar<T, N, std::index_sequence<Is...>>: bar<T, N - 1> {
    using bar<T, N - 1>::operator();
    auto operator()(typer<T, Is>... ts) {
        return std::array<T, N>{{ts...}};
    }
};

template <class T>
struct bar<T, 0, std::index_sequence<>> {
    auto operator()() {
        return std::array<T, 0>{{}};
    }
};

bar<> foo;

int main() {
    foo({}, {});
}

[live demo]

答案 1 :(得分:2)

好吧,如果你有能力改变语法位,这是我设法找到的最好的:

#include <array>

// to_array implementation taken from 
// http://en.cppreference.com/w/cpp/experimental/to_array
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
    return { {a[I]...} };
}
}

template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
    return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
// End of to_array implementation

struct blah { };

template<std::size_t N>
constexpr auto foo(const blah(&arr)[N])
{
    return to_array(arr);
}

int main()
{
    auto res = foo({{}, {}});
    return 0;
}

如您所见,foo({}, {})成了foo({{}, {}})。 这是一个工作示例:https://ideone.com/slbKi3

您想要它的方式(foo({}, {}))的问题是编译器无法知道它应该将{}转换为什么。

我试图找到一种方法让它知道,但它根本就没有听。

答案 2 :(得分:2)

如果您按照Telokis的建议接受添加支持级别foo()

auto res = foo( { {}, {} } );

你可以使用Telokis提出的C风格的数组技巧和一个简单的循环来初始化返回值

template <std::size_t N>
constexpr std::array<blah, N> foo (const blah(&arr)[N])
 {
   std::array<blah, N> ret;

   for ( auto i = 0U ; i < N ; ++i )
      ret[i] = arr[i];

   return ret;
 }

不幸的是,operator[]的{​​{1}}只有std::array才从C ++ 17开始,所以前面的constexpr实际上只有foo从C +开始17。

所以你可以打电话给

constexpr

也在C ++ 11和C ++ 14中,但是

auto res = foo( { {}, {} } );

仅从C ++ 17开始。