149
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?

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Mark
  • 2,181
  • 3
  • 19
  • 28
  • 5
    Note that this is no longer a problem in C++17. See https://stackoverflow.com/questions/49707184/explicit-specialization-in-non-namespace-scope-does-not-compile-in-gcc – cppBeginner Jun 20 '18 at 08:17

5 Answers5

111

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);
    }
};
ctor
  • 5,938
  • 2
  • 26
  • 37
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • 9
    *incompliant in this case*: as always :) ? Templates and VC++ don't mix that well :/ – Matthieu M. Jun 16 '10 at 11:21
  • 11
    It's non-compliant in a sense that it will let you do something that the Standard normally doesn't allow - which isn't a problem for code that is conformant to begin with (you write such code, right? ~). The real conformance problems are when it won't compile something that the Standard requires to compile, or will behave differently from what is specified. – Pavel Minaev Jun 16 '10 at 22:26
  • 2
    Like the subtle pitfalls arising from the missing two-phase lookup ... :| – Georg Fritzsche Jun 16 '10 at 22:33
  • Georg, Thanks for you answer....You actually delegate type deduction to Detail::Verify, so it is not a real CConstraint::Verify, but it works.) – Konstantin Burlachenko Aug 17 '15 at 10:24
  • 39
    Why would the language developers do this to programmer developers? Were they thinking, `How can we make this language any more difficult to read and write?` – Adrian Mar 22 '17 at 01:42
  • 1
    i'm also wondering about thi, is there any particular reason on why the standard forbid this? – bysreg Mar 26 '17 at 00:03
  • 1
    MSVC is "non-compliant" in failing to issue a diagnostic message. In all other respects there's nothing non-compliant in supporting this as an *extension*, unless you can show that it breaks compliant code. Extensions are not non-compliance issues. – AnT stands with Russia Feb 10 '18 at 13:48
  • 9
    This answer is not correct anymore, specialization is now allowed in class scope in conformant C++14 (& later) compilers : https://wg21.cmeerw.net/cwg/issue727 – Jean-Michaël Celerier Sep 05 '19 at 10:14
  • 1
    @Adrian imho in some cases this ruling increases readability... having a dozen of specializations swarming inside of class is a chore to parse. For human – Swift - Friday Pie Nov 22 '19 at 18:11
  • 2
    Since this is currently the top google result, I'd suggest we edit this answer to include what Jean-Michaël Celerier said. Or maybe link to [this](https://stackoverflow.com/questions/49707184/explicit-specialization-in-non-namespace-scope-does-not-compile-in-gcc), which is more up to date. In the end, I disagree with what Swift said and I think that this ruling only hurts readability. Well, he did say "in some cases" though. Anyway, I think now it is more a matter of GCC devs being stubborn than anything else. Both MSVC and CLANG can handle those specializations. – user1593842 May 03 '20 at 19:32
104

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>)
  {

  }
};
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Thanks a lot. I was looking for this also as I need to access this. Wish I could select 2 answers. – Mark Jun 18 '10 at 03:20
  • 8
    If I were you, I'd choose this answer. @Johannes: Your answer is just perfect, thanks. – Alaa Eldin Dec 27 '12 at 09:47
  • Thank you, thank you, thank you, Johannes Schaub, for this answer. – Rethunk Jan 03 '15 at 00:48
  • 3
    This answer is a lot more useful than the accepted one. – Roel Feb 09 '16 at 10:03
  • 3
    Any changes since C++11 came around? – gipouf Dec 02 '16 at 19:23
  • because `templated Verify` functions are private, `struct identity` can be put inside the class as private type. – Nick Aug 03 '17 at 11:12
  • I tried this solution and it didn't work for me until I realized that the public function "Verify" must be called with a type. Like: `Verify(..)` or `Verify(...)`. The compiler cannot deduce it automatically. – Eyal Jun 16 '20 at 22:33
23

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.

bop
  • 555
  • 3
  • 5
5

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[])
{
}
vitke
  • 75
  • 1
  • 1
  • 2
    Default template arguments aren't allowed in C++03, only in C++0x/11. – Xeo Jun 02 '11 at 11:09
  • 3
    Sorry, I was wrong: you cannot partially specialise a function. – vitke Jun 02 '11 at 11:13
  • @Xeo: I guess you meant not allowed on functions in C++03? "A default template-argument is a template-argument (14.3) specified after `=` in a template-parameter. A default template-argument may be specified for any kind of template-parameter (type, non-type, template). A default template-argument may be specified in a class template declaration or a class template definition. **A default template-argument shall not be specified in a function template declaration or a function template definition, nor in the template-parameter-list of the definition of a member of a class template.**" – Ben Voigt Jan 03 '18 at 21:52
2

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.

M. Tibbits
  • 8,400
  • 8
  • 44
  • 59