可变参量子集

时间:2019-08-20 04:16:22

标签: c++ c++11 templates recursion variadic-templates

我正在尝试获取当前类包装器的可变参数的子集,以实例化一个新的

目前我有这个:

// Reference: https://stackoverflow.com/questions/27941661/generating-one-class-member-per-variadic-template-argument
// Template specialization
template<typename T, typename... Next> class VariadicClass;

// Base case extension
template <typename T>
class VariadicClass<T> {
private:
    T value_;
protected:
    void SetField(T & value) {
        value_ = value;
    }

    T & GetField() {
        return value_;
    }
};

// Inductive case
template <typename T, typename ... Next>
class VariadicClass : public VariadicClass<T>, public VariadicClass<Next...> {
public:

    // Copy the values into the variadic class
    template <typename F>
    void Set(F f) {
        this->VariadicClass<F>::SetField(f);
    }

    // Retrieve by reference
    template <typename F>
    F & Get() {
        return this->VariadicClass<F>::GetField();
    }
};

我想实现的目标如下:

[C]: A subset of Args...

VariadicClass<[C]> * Filter(VariadicClass<Args...> input) {
   return new VariadicClass<[C]>(GetSubsetFrom(input, [C]));
}

VariadicClass<int, bool, char> class1;
VariadicClass<int, bool> * variadic = Filter(class1);

您可以假设在可变参数类中每种类型只有一次,并且我将始终询问当前可变参数类型的子集。我不知道目前在C ++ 11中是否可行? 谢谢您的帮助。

2 个答案:

答案 0 :(得分:3)

在我看来,您正在尝试重新发明轮子(在这种情况下,“轮子”为std::tuple)。

无论如何,你的要求对我来说似乎很简单

template <typename ... As1, typename ... As2>
VariadicClass<As1...> * Filter(VariadicClass<As2...> in)
 {
   using unused = int[];

   auto ret = new VariadicClass<As1...>();

   (void)unused { 0, (ret->template Set<As1>(in.template Get<As1>()), 0)... };

   return ret;
 }

我看到的问题是As1...类型(返回的VariadicClass的类型)不能由返回的值推导,所以您不能写

 VariadicClass<int, bool> * variadic = Filter(class1);

您必须明确调用As1...的{​​{1}}类型,所以

Filter()

或者也许更好

 VariadicClass<int, bool> * variadic = Filter<int, bool>(class1);

以下是完整的编译示例

 auto variadic = Filter<int, bool>(class1);

不需要主题的建议:您正在使用C ++ 11,所以...尝试避免直接使用指针,并尝试使用智能指针(#include <iostream> template <typename, typename...> class VariadicClass; template <typename T> class VariadicClass<T> { private: T value_; protected: void SetField (T & value) { value_ = value; } T & GetField () { return value_; } }; template <typename T, typename ... Next> class VariadicClass : public VariadicClass<T>, public VariadicClass<Next...> { public: template <typename F> void Set (F f) { this->VariadicClass<F>::SetField(f); } template <typename F> F & Get() { return this->VariadicClass<F>::GetField(); } }; template <typename ... As1, typename ... As2> VariadicClass<As1...> * Filter(VariadicClass<As2...> in) { using unused = int[]; auto ret = new VariadicClass<As1...>(); (void)unused { 0, (ret->template Set<As1>(in.template Get<As1>()), 0)... }; return ret; } int main() { VariadicClass<int, bool, char> c1; c1.Set<int>(42); c1.Set<bool>(true); c1.Set<char>('Z'); auto pC2 = Filter<int, bool>(c1); std::cout << pC2->Get<int>() << std::endl; std::cout << pC2->Get<bool>() << std::endl; delete pC2; } std::unique_ptr等)代替。

答案 1 :(得分:1)

首先,我认为您不应该编写自己的可变参数类,因为我们已经有了std::tuple

我想知道您坐在c++11上是因为它已经很老了。甚至c++14都已过时,但是如果您可以切换,解决方案将非常简单:

template < typename DATA, typename FILTER, std::size_t... Is>
auto Subset_Impl( const DATA& data, FILTER& filter, std::index_sequence<Is...> )
{
    filter = { std::get< typename std::remove_reference<decltype( std::get< Is >( filter ))>::type>( data )... };
}

template < typename DATA, typename FILTER, typename IDC = std::make_index_sequence<std::tuple_size<FILTER>::value >>
auto Subset( const DATA& data, FILTER& filter )
{
    return Subset_Impl( data, filter,  IDC{} );
}

int main()
{
    std::tuple< int, float, std::string, char > data { 1, 2.2, "Hallo", 'c' };
    std::tuple< float, char > filter;

    Subset( data, filter );

    std::cout << std::get<0>( filter ) << " " << std::get<1>( filter ) << std::endl;
}

如果您真的想使用过时的标准,则可以轻松实现自己标准库中缺少的部分。这里回答了一个相关的问题:get part of std::tuple

如何定义助手模板也可以在https://en.cppreference.com/w/cpp/utility/integer_sequence

上看到