ChatGPT解决这个技术问题 Extra ChatGPT

Explicit specialization in non-namespace scope [duplicate]

This question already has answers here: C++ syntax for explicit specialization of a template function in a template class? (9 answers) Closed 7 years ago.

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?

Note that this is no longer a problem in C++17. See stackoverflow.com/questions/49707184/…

c
ctor

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);
    }
};

incompliant in this case: as always :) ? Templates and VC++ don't mix that well :/
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.
Like the subtle pitfalls arising from the missing two-phase lookup ... :|
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?
This answer is not correct anymore, specialization is now allowed in class scope in conformant C++14 (& later) compilers : wg21.cmeerw.net/cwg/issue727
J
Johannes Schaub - litb

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

  }
};

Thanks a lot. I was looking for this also as I need to access this. Wish I could select 2 answers.
If I were you, I'd choose this answer. @Johannes: Your answer is just perfect, thanks.
Thank you, thank you, thank you, Johannes Schaub, for this answer.
This answer is a lot more useful than the accepted one.
Any changes since C++11 came around?
b
bop

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.


1st sentence is on the money: "gcc doesn't allow inline template specialization".
Removing the template<> worked for me as well.
v
vitke

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[])
{
}

Default template arguments aren't allowed in C++03, only in C++0x/11.
Sorry, I was wrong: you cannot partially specialise a function.
@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."
M
M. Tibbits

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.


You cannot partially specialize a function