Search code examples
c++template-specializationpartial-specialization

Template specialization with nested unspecialized type


I'm having trouble working out the syntax for a nested partial template specialization. I think that's the right way of putting it anyway. What I want is an as() function which returns a casted value. In most cases static_cast will work fine so I have a generic version which does that, but in some cases I want to get specific. The trouble I'm having is when trying to return two similar templated class types, using a common typename.

template<typename ClassType>
class Generic
{
public:
    // Constructors/etc excluded

    template<typename CastType>
    CastType as() const;

private:
    ClassType m_value;
};

// Templated version:
template<typename ClassType> template<typename CastType> inline
CastType Generic<ClassType>::as<CastType>() const
{
    return static_cast<CastType>(m_value);
}

That's the set-up. Actually I'm not 100% sure if that's the best way to do it, but it compiles in GCC and seems to work, so.. anyway. Now I want to specialize with another templated type (in this case, Eigen::Matrix<T,4,1> -- but perhaps std::vector or another as well might be used in time, i.e. to cast from a std::vector<T> to a std::list<T>) that's partialy templated:

template<> template<typename CastType> inline
CastType Generic<Eigen::Matrix<CastType,4,1> >::as<CastType>() const
{
    return m_value[0];
}

Does this make any sense? What about a slightly different version where I take Eigen::Matrix of differing sizes and handle them specially?

template<> template<typename CastType> inline
Eigen::Matrix<CastType,3,1> Generic<Eigen::Matrix<CastType,4,1> >::as<Eigen::Matrix<CastType,3,1>() const
{
    return Eigen::Matrix<CastType,3,1>( m_value[0], m_value[1], m_value[2] );
}

I know the above two code bits don't work and the syntax is probably horrible, this is what I'm trying to work out. Forgive if this is a duplicate. I looked at several similar questions but none seemed quite to be about this, or I just didn't see it.


Solution

  • Since a function can't be partially specialize, we partially specialize a functionoid-thingy instead, and make the function simply use the specialized class.

    //generic version
    template<typename ClassType, typename CastType> class As { 
    public: CastType operator()(const ClassType& b)
        {return static_cast<CastType>(b);}
    };
    //specialization
    template<> class As<int, char* > { 
    public: char* operator()(const int& b)
        {throw b;} //so we know it worked
    };
    
    //generic class 
    template<typename ClassType>
    class Generic
    {
    public:
        Generic() {m_value=0;} //codepad made me put this in
        // Constructors/etc excluded
    
        template<typename CastType>
        CastType as() const; //as function
    
    private:
        ClassType m_value;
    };
    
    // as function simply grabs the right "As" class and uses that
    template<typename ClassType> template<typename CastType> inline
    CastType Generic<ClassType>::as() const
    {
        As<ClassType, CastType> impl;
        return impl(m_value);
    }
    
    //main, confirming that it compiles and runs (though I didn't check b...)
    int main() {
        Generic<int> gint;
        float b = gint.as<float>();
        char* crash = gint.as<char*>();
    }
    

    code at: http://codepad.org/oVgCxTMI results:

    uncaught exception of type int
    Aborted.