簡體   English   中英

沒有虛擬或繼承的多態向量

[英]polymorphic vector without virtual or inheritance

我正在嘗試實現一個向量,該向量可以采用多種類型的元素,並且可以對所有元素應用函數。 使用基類,虛函數和繼承很容易做到這一點,但是我明確地不想使用它。 這是我到目前為止的距離:

#include <iostream>
#include <vector>
#include <tuple>

// this will be my new polymorphic vector;
template<typename... Ts>
class myvector {
    std::tuple<std::vector<Ts>...> vectors;

    template <template<typename> class funtype>
    void for_each() {
    }

    template <template<typename> class funtype, typename X, typename... Xs>
    void for_each() {
        std::vector<X>& vector = std::get<std::vector<X>>(vectors);
        for ( X& x : vector ) {
            funtype<X> fun;
            fun(x);
        }
        for_each<funtype, Xs...>();
    }

public:
    template <typename T>
    void push_back(const T& t) {
        std::vector<T>& vector = std::get<std::vector<T>>(vectors);
        vector.push_back(t);
    }

    template <typename T>
    void pop_back() {
        std::vector<T>& vector = std::get<std::vector<T>>(vectors);
        vector.pop_back();
    }

    /* here I would like to pass a function, or function object that 
     * can be expanded to all underlying types. I would prefer to just 
     * give a function name, that has an implementation to all types in Ts
     */
    template <template<typename> class funtype>
    void ForEach() {
        for_each<funtype,Ts...>();
    }
};


struct foo {
};

struct bar {
};

template <typename T>
void method(T& t);

template<>
void method(foo& b) {
    std::cout << "foo" << std::endl;
}

template<>
void method(bar& b) {
    std::cout << "bar" << std::endl;
}

int main()
{
    myvector<foo,bar> mv;
    mv.push_back( foo{} );
    mv.push_back( bar{} );
    mv.ForEach<method>();
}

目前,我感到有些困惑,希望您能給我一些進一步建議。

常見的解決方案是將函數對象與一組operator()

struct my_fun_type
{
    void operator()(foo&) const
    { std::cout << "foo\n"; }

    void operator()(bar&) const
    { std::cout << "bar\n"; }
};

這允許將“重載函數”的“集合”傳遞給算法,狀態,並且使用起來相當方便:

my_algorithm(my_fun_type{});

如果要添加對此類功能對象的支持,可以按以下方式定義ForEach

template <typename Elem, typename Fun>
void for_each(Fun&& fun) {
    std::vector<Elem>& vector = std::get<std::vector<Elem>>(vectors);
    for ( Elem& e : vector ) {
        fun(x);
    }
}

template <typename Fun>
void ForEach(Fun&& fun) {
    int dummy[] = { 0, (for_each<Ts>(fun), 0)... };
    (void)dummy;
}

這個dummy是為Ts所有類型調用for_each的技巧。 (void)dummy用於禁止編譯器警告(永遠不會讀取dummy )。

您可以在其他問答中進一步了解此技術,例如問答。

Fun&&不是右值引用,而是通用引用


請注意,上面的示例與許多標准庫算法不同,后者按值獲取函數對象:

template <typename Elem, typename Fun>
void for_each(Fun fun) {
    std::vector<Elem>& vector = std::get<std::vector<Elem>>(vectors);
    std::for_each(vector.begin(), vector.end(), std::move(fun));
}

template <typename Fun>
void ForEach(Fun fun) {
    int dummy[] = { 0, (for_each<Ts>(fun), 0)... };
    (void)dummy;
}

要傳遞一組重載的自由函數,我們可以將它們包裝在一個函數對象中(感謝@Yakk的建議):

struct method_t
{
    template<class... Ts>
    void operator()(Ts&&... ts) const
    { method( std::forward<Ts>(ts)... ); }
};

在C ++ 1y中,使用多態lambda可以用更少的樣板創建這樣的函數對象類型:

[](auto&&... pp)
{ method( std::forward<decltype(pp)>(pp)... ); }

暫無
暫無

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

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