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

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

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

#include <array>
struct blah { };

template<typename... Args>
constexpr auto foo(Args&&... args)
{
    return std::array<blah, sizeof...(Args)>{{ args... }};
}

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

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

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,因为我无法计算要传递给 array 类型的参数的数量。 我尤其不想输入 foo(blah{}, blah{});

我的可能性是什么?

最佳答案

稍微扩展了一点approach of Jarod42对于懒惰者 (C++17):

#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]

关于在参数中强制执行单一类型的 C++ 参数包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47470874/

相关文章:

c++ - boost::mutex,pthread_mutex_destroy 失败 - 调试建议?

c++ - 为什么模板特化需要内联定义?

c++ - boost::spirit ,如何获取占位符的 "value"

c++ - 递归 Variadic 模板函数的编译错误

c++ - 如何使用 std::pair 将两个 std::vector 合并为一个 std::vector

c++ - 是否可以在 C++11 中编写宏 existenceof(S,f) 或 hasfield(S,f)?

c++ - throw() 函数是否应该始终在异常时展开堆栈并允许捕获异常,或者必须调用 std::terminate?

c++ - 将字符串推送到私有(private)成员 vector

c++ - 如何将 unicode 字符与 boost::spirit 匹配?

c++ - 如何编译时检测重载重要模板的函数?