Explicit specialization in non-namespace scope

C++TemplatesGcc

C++ Problem Overview


template<typename T>
class CConstraint
{
public:
    CConstraint()
    {
    }

    virtual ~CConstraint()
    {
    }
	
    template <typename TL>
    void Verify(int position, int constraints[])
    {		
    }

    template <>
    void Verify<int>(int, int[])
    {	
    }
};

Compiling this under g++ gives the following error:

> Explicit specialization in non-namespace scope 'class CConstraint'

In VC, it compiles fine. Can anyone please let me know the workaround?

C++ Solutions


Solution 1 - C++

VC++ is non-compliant in this case - explicit specializations have to be at namespace scope. C++03, §14.7.3/2:

> An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member.
> An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.

Additionally you have the problem that you can't specialize member functions without explicitly specializing the containing class due to C++03, §14.7.3/3, so one solution would be to let Verify() forward to a, possibly specialized, free function:

namespace detail {
    template <typename TL> void Verify     (int, int[]) {}
    template <>            void Verify<int>(int, int[]) {}
}

template<typename T> class CConstraint {
    // ...
    template <typename TL> void Verify(int position, int constraints[]) {
        detail::Verify<TL>(position, constraints);
    }
};

Solution 2 - C++

Another way to solve it is by delegating to a private function and overloading that function. This way you still have access to member data of *this and to the outer template parameter type.

template<typename T>
struct identity { typedef T type; };

template<typename T>
class CConstraint
{
public:

  template <typename TL>
  void Verify(int position, int constraints[])
  {
    Verify(position, constraints, identity<TL>());
  }

private:
  template<typename TL>
  void Verify(int, int[], identity<TL>)
  {

  }

  void Verify(int, int[], identity<int>)
  {

  }
};

Solution 3 - C++

Just take the template specialization outside the class declaration. gcc doesn't allow inline template specialization.

As another option, just deleting line template<> seems to work for me.

Solution 4 - C++

Even better: you can combine partial specialisation with default template arguments. This way modification to the VC++ code are minor, because calls to the specialised function do not need to be modified.

template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}

template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}

Solution 5 - C++

You may not be able to explicitly specialize the member template, but you can partially specialize it. If you add a second parameter "int dummyParam" and also add it to the specialization, it should work with both compilers.

Not that I knew this more than 10 seconds ago, but googling on the same error, I ran into this link and it worked for my member template specialization.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarkView Question on Stackoverflow
Solution 1 - C++Georg FritzscheView Answer on Stackoverflow
Solution 2 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 3 - C++bopView Answer on Stackoverflow
Solution 4 - C++vitkeView Answer on Stackoverflow
Solution 5 - C++M. TibbitsView Answer on Stackoverflow