使函数只取出每对中的第一个值

时间:2017-12-28 02:57:47

标签: c++ function variadic-templates c++17 template-meta-programming

我需要使一个函数只接受传递给它的参数的每个std::pair的第一个值。传递的值不是std::pair类型的值将不加改变地使用。我的以下解决方案仅适用于带有两个参数的函数。我需要知道如何将它推广到任何数量的传递参数。

#include <type_traits>

template <typename T, typename = void>
struct has_first_type : std::false_type { };

template <typename T>
struct has_first_type<T, std::void_t<typename T::first_type>> : std::true_type { };

template <typename R, typename T, typename U, typename = void> struct act_on_first;

template <typename R, typename T, typename U>
struct act_on_first<R, T, U, std::enable_if_t<has_first_type<T>::value && has_first_type<U>::value>> {
    template <typename F>
    static R execute (const T& t, const U& u, F f) {
        return f(t.first, u.first);
    }
};

template <typename R, typename T, typename U>
struct act_on_first<R, T, U, std::enable_if_t<has_first_type<T>::value && !has_first_type<U>::value>> {
    template <typename F>
    static R execute (const T& t, const U& u, F f) {
        return f(t.first, u);
    }
};

template <typename R, typename T, typename U>
struct act_on_first<R, T, U, std::enable_if_t<!has_first_type<T>::value && has_first_type<U>::value>> {
    template <typename F>
    static R execute (const T& t, const U& u, F f) {
        return f(t, u.first);
    }
};

template <typename R, typename T, typename U>
struct act_on_first<R, T, U, std::enable_if_t<!has_first_type<T>::value && !has_first_type<U>::value>> {
    template <typename F>
    static R execute (const T& t, const U& u, F f) {
        return f(t, u);
    }
};

struct foo {
    template <typename... Args>
    std::size_t operator()(Args&&...) { return sizeof...(Args); }  // Simple example only.
};

template <typename T, typename U>
std::size_t bar (const T& t, const U& u) {
    return act_on_first<std::size_t, T, U>::execute(t, u, foo());
}

// Testing
#include <iostream>

int main() {
    std::pair<int, bool> k = {3, true};
    std::pair<int, char> m = {5, 't'};
    std::cout << bar(k,m) << '\n';  // 2
    std::cout << bar(k,5) << '\n';  // 2
    std::cout << bar(3,m) << '\n';  // 2
    std::cout << bar(3,5) << '\n';  // 2
}

1 个答案:

答案 0 :(得分:7)

写一个变换器,它可以为你提供.first或者只返回它的参数:

template <typename T> T const& take_first(T const& x) { return x; }
template <typename T, typename U>
T const& take_first(std::pair<T, U> const& p) { return p.first; }

template <typename... Args>
std::size_t bar(Args const&... args) {
    return foo{}(take_first(args)...);
}