簡體   English   中英

通常在元組的每個元素上調用成員函數

[英]Generically call member function on each element of a tuple

第一步:展開元組並將元素傳遞給函數:

我有一個帶N個參數的函數

void func(int, double, char);

和一個匹配類型的元組

std::tuple<int, double, char> tuple;

根據這個stackoverflow問題 ,我能夠擴展元組並調用該函數。

第二步:展開元組並將每個元素上調用成員函數的結果傳遞給函數:

更進一步,我的元組包含一個類模板的多個實例:

template<typename T>
struct Foo;

std::tuple<Foo<int>, Foo<double>, Foo<char>>

Foo有一個成員函數, Foo<T>::get()返回一個T類型的值。

根據這個stackoverflow的答案 ,我有下面的工作代碼,它擴展元組並在每個元素上調用element.get() ,最終將結果傳遞給func

不幸的是,我已經對element.get()的調用進行了硬編碼

第三步:在每個元組元素上調用哪個成員函數的規范:

(這是我正在尋求幫助的事情)

是否有可能使這個通用? 也就是說,通過調用哪個成員函數apply ,因此它作為一個通用的工具?

我想也許我可以使用std::mem_fn來包裝一個函數( std::mem_fn(&Foo::get) )並將結果對象傳遞給apply ,但是這不起作用,因為Foo是一個類模板:

error: 'template<class T> struct Foo' used without template parameters

有沒有辦法讓這個通用?

下面的工作示例:

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

template<size_t...>
struct Seq
{ };

template<size_t N, size_t... Sq>
struct GenSeq : GenSeq<N - 1, N - 1, Sq...>
{ };

template<size_t... Sq>
struct GenSeq<0, Sq...>
{
    using type = Seq<Sq...>;
};

/////////////////////////////////////

struct Invoker
{
    template<typename Func, typename Tuple, size_t... Sq>
    static auto invoke(Func func, const Tuple& tuple, Seq<Sq...>)
        -> decltype(func(std::get<Sq>(tuple).get()...))
    {
        // calls the .get() member on each object in the tuple
        // I would like to make this generic
        return func(std::get<Sq>(tuple).get()...);
    }

    template<typename Func, typename... Args>
    static auto apply(Func func, const std::tuple<Args...>& args)
        -> decltype(invoke(func, args, typename GenSeq<sizeof...(Args)>::type()))
    {
        return invoke(func, args, typename GenSeq<sizeof...(Args)>::type());
    }
};

template<typename Func, typename Tuple>
inline auto apply(Func func, const Tuple& tuple)
    -> decltype(Invoker::apply(func, tuple))
{
    return Invoker::apply(func, tuple);
}

///////////////////////////////////////

template<typename T>
struct Foo
{
    T i;
    auto get() const -> decltype(i) { return i; }
};

template<typename... Ts>
struct Bar
{
    Bar(Ts... ts) : tuple(std::make_tuple(Foo<Ts> { ts }...)) {}
    std::tuple<Foo<Ts>...> tuple;
};

void func(int i, double d, char c)
{
    std::cout << i << ", " << d << ", " << c << std::endl;
}

int main()
{
    Bar<int, double, char> bar { 4, 1.23, 'a' };
    apply(func, bar.tuple);
}

您不能使用mem_fn創建一個在異構類型的對象上調用成員函數的包裝器,因為mem_fn創建的包裝器將指針包裝到特定類型的特定成員。

訣竅是使用模板化函數調用運算符傳遞一些東西,它可以接受任何適當的類型並調用成員函數。

在C ++ 14中,傳遞一個多態lambda:

[](auto&& obj) -> decltype(auto) { return std::forward<decltype(obj)>(obj).get(); }

對於C ++ 11,您需要手動編寫等效的仿函數:

struct call_get {
    template<class T>    
    auto operator()(T&& obj) const -> decltype(std::forward<T>(obj).get()) {
         return std::forward<T>(obj).get(); 
    } 
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM