简体   繁体   中英

Deduce template parameter from member variable in constructor

I have a C++ library which is a wrapper for a C library. A factory class Creator creates objects of which each represents parts of the functionality of the C library. These class constructors are private to ensure that all objects are created through that Creator class because the C library requires some internal magic (which I omitted in the following, simplified example).

It all works, but I have the following "problem":

In class UsesAandB I have to specify the template parameter of A<> twice: Once in the member declaration ( std::shared_ptr<A<int>> ) and once in the initialization list of the constructor ( creator->createA<int> ).

Since I already know that member aInt will be of type std::shared_ptr<A<int>> , how can I use this knowledge to call the corresponding createA<int>() method in the constructor without repeating int or how can I avoid the call to createA<int>() at all?

#include <memory>

class Creator;

template<typename T>
class A
{
    friend class Creator;
private:
    A(int param) {}
    T value;
};

class B
{
    friend class Creator;
private:
    B(){}
};

class Creator
{
public:
    template<typename T>
    std::shared_ptr<A<T>> createA(int param) { return std::shared_ptr<A<T>>(new A<T>(param)); }
    std::shared_ptr<B> createB() { return std::shared_ptr<B>(new B());}
};

class UsesAandB
{
public:
    UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(creator->createA<int>(0)),
          aDouble(creator->createA<double>(1)),
          b(creator->createB())
   {

   }
private:
    std::shared_ptr<Creator> creator;
    std::shared_ptr<A<int>> aInt;
    std::shared_ptr<A<double>> aDouble;
    std::shared_ptr<B> b;
};

int main()
{
    auto creator = std::make_shared<Creator>();
    UsesAandB u(creator);
    return 0;
}

To get the type from the shared_ptr , you need to pass it to a template function like this one:

template <typename U>
shared_ptr< A<U> > CreateA( std::shared_ptr<Creator>& c,
                            const shared_ptr< A<U> >& p,
                            const U& val )
{
    return c->createA<U>(val);
}

Then simply:

aInt(CreateA(creator, aInt, 0 )),

Sample here - http://ideone.com/Np7f8t

My idea, don't know if it solves anything, but you do eliminate the chance of having different types in the declaration and constructor call.

template<typename T>
class A
{
    friend class Creator;
private:
    typedef T type;
    A(int param) {}
    T value;
};

class UsesAandB
{
typedef std::shared_ptr<A<int>> sharedA;

public:
    UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(creator->createA<sharedA::element_type::type>(0)),
          aDouble(creator->createA<double>(1)),
          b(creator->createB())
   {

   }

private:
    std::shared_ptr<Creator> creator;
    sharedA aInt;
    std::shared_ptr<A<double>> aDouble;
    std::shared_ptr<B> b;
};

You could add the following static template function

template <class T>
static std::shared_ptr<T> create1(std::shared_ptr<Creator> &creator, std::shared_ptr<T> &,T value)
{
   return creator->createA(value) ;
}

An then initialize like this:

UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(create1((creator, aInt, 0)),
          aDouble(create1(creator, aDouble, 1)),
          b(creator->createB())
   {

   }

create1 requires the shared pointer only to deduce the right type. A problem is that this code should raise a warning (this used in nitializer list)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM