开发者

C++ auto detection of template arguments?

I am trying to define a recursive construct like a task farming. Here, I am trying for two operands which recursively can work for any number of operands as it can nest itself.

template <typename T1, typename T2>
class Farm
{
开发者_开发知识库  private:
    T1 *task1;
    T2 *task2;
  public:
    // save them so that I can use them when invoking call operator
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }

    void operator()()
    {
      // invoke call operator, meaning a farm could be a task (arbitrary nesting)
      (*task1)();
      (*task2)();
    }
};
int main()
{
    ... create two pointer(A *a, B *b...)
    Farm(a,b); // error: missing template arguments before ‘(’ token

    Farm<A, B>(a,b); // in this works, it works
}

The problem is with auto-detection of template arguments which is not working in this case. What am I doing wrong and how could I achieve this template parameters implicit detection by gcc compiler.

Thanks!


Before C++17, classes/constructors didn't autodetect types like functions do. You need to write a wrapper function to create your class.

This is done as follows and called the Object Generator pattern. (thanks @Itjax!)

template <typename T1, typename T2>
Farm<T1, T2> makeFarm(T1* a, T2* b) {
      return Farm<T1,T2>(a,b);
}

// silly example
Farm<T1,T2> farm = makeFarm(a,b);

// better example
template<typename T>
void plow(T& farm) { farm.applyTractor(...); }

void blah() {
    plow(makeFarm(b,a)) 
}

This pattern emerges quite a lot when using lambda/bind/foreach and similar parts, when you want to create a temporary object of a templated class with some arguments and avoid specifying their type, usually sending it into another template function (std::for_each) or polymorphic object (std::function).

Note: The generator function usually inlines and with copy-elision optimization there will probably be no copy-constructor(s) called in your code at all. If you cannot copy your object, makeFarm() should return a smart pointer instead (std::unique_ptr is preferred in modern C++).


The usual workaround is to provide a template function which returns the real implementation. The standard C++ library uses this alot, e.g. with std::make_pair.

Example:

template<typename T>
struct foo_t {
    ...
};

template<typename T>
foo_t<T> foo(T const &f) {
    return foo_t<T>(f);
}

This works because for functions the compiler is allowed to deduce the typenames from the parameter list.


You could add a base class for the class Farm:

class FarmBase
{
  public:
    virtual ~FarmBase(){}

    virtual void operator()() = 0;
};


template <typename T1, typename T2>
class Farm : public FramBase
{
  private:
    T1 *task1;
    T2 *task2;
  public:
    // save them so that I can use them when invoking call operator
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }
    virtual ~Farm(){}

    virtual void operator()()
    {
      // invoke call operator, meaning a farm could be a task (arbitrary nesting)
      (*task1)();
      (*task2)();
    }
};
template< typename A, typename B >
FarmBase* Create( A *a, B *b )
{
  return new Farm< A, B >( a, b );
}

then the main looks like:

int main()
{
    //... create two pointer(A *a, B *b...)

    FarmBase *fobj = CreateFarm( a, b );
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜