簡體   English   中英

具有多個參數包的C ++方法

[英]C++ method with multiple parameter packs

考慮以下用於變體類的簡化代碼。 其中大多數是出於提供信息的目的,問題是關於conditional_invoke方法。

// Possible types in variant.
enum class  variant_type { empty, int32, string };

// Actual data store.
union variant_data { 
    std::int32_t val_int32;
    std::string val_string;
    inline variant_data(void) { /* Leave uninitialised */ }
    inline ~variant_data(void) { /* Let variant do clean up. */ }
};

// Type traits which allow inferring which type to use (these are actually generated by a macro).
template<variant_type T> struct variant_type_traits { };
template<class T> struct variant_reverse_traits { };

template<> struct variant_type_traits<variant_type::int32> {
    typedef std::int32_t type;
    inline static type *get(variant_data& d) { return &d.val_int32; }
};

template<> struct variant_reverse_traits<std::int32_t> {
    static const variant_type type = variant_type::int32;
    inline static std::int32_t *get(variant_data& d) { return &d.val_int32; }
};

template<> struct variant_type_traits<variant_type::string> {
    typedef std::string type;
    inline static type *get(variant_data& d) { return &d.val_string; }
};

template<> struct variant_reverse_traits<std::string> {
    static const variant_type type = variant_type::string;
    inline static std::string *get(variant_data& d) { return &d.val_string; }
};

// The actual variant class.
class variant {
public:

    inline variant(void) : type(variant_type::empty) { }

    inline ~variant(void) {
        this->conditional_invoke<destruct>();
    }

    template<class T> inline variant(const T value) : type(variant_type::empty) {
        this->set<T>(value);
    }

    template<class T> void set(const T& value) {
        this->conditional_invoke<destruct>();
        std::cout << "Calling data constructor ..." << std::endl;
        ::new (variant_reverse_traits<T>::get(this->data)) T(value);
        this->type = variant_reverse_traits<T>::type;
    }

    variant_data data;
    variant_type type;

    private:

    template<variant_type T> struct destruct {
        typedef typename variant_type_traits<T>::type type;
        static void invoke(type& v) {
            std::cout << "Calling data destructor ..." << std::endl;
            v.~type(); 
        }
    };

    template<template<variant_type> class F, class... P>
    inline void conditional_invoke(P&&... params) {
        this->conditional_invoke0<F, variant_type::int32, variant_type::string, P...>(std::forward<P>(params)...);
    }

    template<template<variant_type> class F, variant_type T, variant_type... U, class... P>
    void conditional_invoke0(P&&... params) {
        if (this->type == T) {
            F<T>::invoke(*variant_type_traits<T>::get(this->data), std::forward<P>(params)...);
        }
        this->conditional_invoke0<F, U..., P...>(std::forward<P>(params)...);
    }

    template<template<variant_type> class F, class... P>
    inline void conditional_invoke0(P&&... params) { }
};

代碼以這種方式工作,即,只要函子的參數列表P...為空,它就可以工作。 如果我添加另一個仿函數

template<variant_type T> struct print {
    typedef typename variant_type_traits<T>::type type;
    static void invoke(type& v, std::ostream& stream) {
        stream << v;
    }
};

並嘗試調用它

friend inline std::ostream& operator <<(std::ostream& lhs, variant& rhs) {
    rhs.conditional_invoke<print>(lhs);
    return lhs;
}

VS 20115編譯器抱怨

錯誤C2672:'variant :: conditional_invoke0':找不到匹配的重載函數

或gcc分別

錯誤:沒有匹配的函數可以調用'variant :: conditional_invoke0>&>(std :: basic_ostream&)'

我猜編譯器無法確定U...何時結束以及P...何時開始。 有什么辦法可以解決此問題?

您必須使兩個參數包都可推導。 也就是說,讓類型和非類型模板參數成為功能參數列表的一部分。 為此,引入一個虛擬結構:

template <variant_type...>
struct variant_type_list {};

然后讓編譯器從函數調用中推斷出variant_type... pack:

template <template <variant_type> class F
        , variant_type T
        , variant_type... U
        , typename... P>
void conditional_invoke0(variant_type_list<T, U...> t
                       , P&&... params)
{
    if (this->type == T)
    {
        F<T>::invoke(*variant_type_traits<T>::get(this->data)
                    , std::forward<P>(params)...);
    }

    this->conditional_invoke0<F>(variant_type_list<U...>{}
                               , std::forward<P>(params)...);
}

要中斷遞歸調用,請使用一個空的variant_type_list引入重載:

template <template <variant_type> class F, typename... P>
void conditional_invoke0(variant_type_list<>, P&&... params) {}

首次調用調用程序時,請提供variant_types作為參數:

this->conditional_invoke0<F>(variant_type_list<variant_type::int32, variant_type::string>{}
                           , std::forward<P>(params)...);

演示

暫無
暫無

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

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