    #include <iostream>
    #include <queue>
    #include <memory>
    
    template <typename T>
    struct LockingQueue
    {
        std::queue<T> s_queue;
    };

    // Option 1
    template < typename CM, template<typename> class SP>
    struct LockingQueue<SP<CM>>
    {
        std::queue< SP<CM> > s_queue;
    };

    // Option 2
    template < typename T, typename R, template<typename,typename> class CM, template<typename> class SP>
    struct LockingQueue<SP<CM<T,R>>>
    {
        std::queue< SP<CM<T,R>> > s_queue;
    };
    
    template <typename TaskData, typename TaskName>
    struct CommonMsg
    {
        TaskData dataType;
        TaskName taskName;
    };
    
    template <typename TaskData, typename TaskName>
    using CommonMsgPtr = std::shared_ptr<CommonMsg<TaskData, TaskName>>;
    
    template <typename TaskData, typename TaskName>
    using CommonMsgConstPtr = std::shared_ptr<const CommonMsg<TaskData, TaskName>>;
    
    // Option 1 alias
    template < typename CM, template<typename> class SP = std::shared_ptr>
    using CommonMsgConstSPtr1 = SP< const CM >;

    // Option 2 alias
    template < typename TaskData = int, typename TaskName = char, template<typename,typename> class CM = CommonMsg, template<typename> class SP = std::shared_ptr>
    using CommonMsgConstSPtr2 = SP< const CM<TaskData, TaskName> >;
    
    int main()
    {
    	LockingQueue< CommonMsgConstSPtr1< CommonMsg<int,char> > > option1;
    	LockingQueue< CommonMsgConstSPtr2<> > option2;
    }