Search code examples
templatesc++11variadic-templatesstatic-if

C++11 Class template method specialization and variadic templates


I am trying to construct the following kind of templated method using GCC and C++11:

class Foo
{
private:
    //Device handle
    cudnnHandle_t handle_;
    //Batch sizes
    std::vector<int> batch_;
public:
    Foo(cudnnHandle_t handle, std::vector<int> batch) : handle_(handle), batch_(batch) {}
    template<typename T, typename... Args> T create(Args&&... args)
    {
        if(std::is_base_of<Element,T>::value)
            return T(handle_,args...);
        if(std::is_same<Block,T>::value)
            return T(handle_,batch_,args...);
    }
};

This however fails to compile due to the return statements. In case where T is Block, return T(handle_,args...) will fail and in case T is a Element base type return T(handle,batch_,args...) will fail.

I tried partial template specialization which is not allowed:

template<typename T, typename... Args> T create(Args&&... args)
{
    return T(handle_,args...);
}
template<typename... Args> Block create<Block>(Args&&... args)
{
    return Block(handle_,batch_,args...);
}

And i tried full template specialization which is apparently not supported for variadic templates by GCC:

template<typename T, typename... Args> T create(Args&&... args)
{
    return T(handle_,args...);
}
template<> Block create<Block,int>(int n)
{
    return Block(handle_,batch_,n);
}

So how would i go about creating a function like create?

Kind regards.


Solution

  • Try taking advantage of SFINAE like this

    template <typename T, typename... Args,
              typename std::enable_if<std::is_base_of<Element, T>::value>::type* = nullptr>
    T create(Args&&... args) {
      return T(handle_, std::forward<Args>(args)...);
    }
    
    template <typename T, typename... Args,
              typename std::enable_if<std::is_same<Block, T>::value>::type* = nullptr>
    T create(Args&&... args) {
      return T(handle_, batch_, std::forward<Args>(args)...);
    }