简体   繁体   中英

template specialization/initializations and namespaces?

What are C++'s rules regarding template specialization and namespace qualification? I had some code that boiled down to the equivalent of the following, and it made me realize that I don't understand C++'s rules regarding template specialization initializations. It seems weird to me firstly that the specializations of g::F<> are even allowed inside h , but given that, I don't know why things act the way they do.

namespace g {

  struct N {
    N(char c):c_(c){}
    char c_;
  };

  template <typename V>
  struct F {
    static N n_s; // <-- want to initialize these for specializations
  };

  namespace h {
    struct X { static constexpr char k{'x'}; };

    template <> N F<char>::n_s{h::X::k};  // OK
    template <> N F<int>::n_s{X::k};      // fails on "‘X’ not declared"
  }
} // namespace g

// Seems weirdest to me. N and F need full qualifications but X doesn't.
template <> g::N g::F<float>::n_s{h::X::k}; // OK also!

The last instantiation/initialization, where the template static member initializer infers the g namespace, makes it seem as though the template acts as though the initializer acts as though it were located in the same spot in code as the template definition itself.

What is the rule of the specification that dictates this behavior? (Note that this was tested on gcc 4.8.1, and looks thus far a bit like a bug...)

The key confusion here is not about specialization, but about qualification. Let's look at the last specialization (in the global namespace) to illustrate this:

template <> g::N g::F<float>::n_s{h::X::k};

As the line starts, you're in the global namespace. Thus, g::N is necessarily qualified, as is g::F<float> .

However, the moment you're past the thing you specialize (ie after n_s ), you're now in the scope of the thing you're specializing, ie inside g::F . All further lookup is done from within this scope, so x must be qualified as h::X .

That said, while it's allowed to specialize things in a namespace that encloses the original namespace, specializing within a nested namespace ( h in your case) looks weird to me, but the standard is mildly ambiguous here, as it says in 14.7.3/2: "An explicit specialization shall be declared in a namespace enclosing the specialized template."

The global namespace encloses F , so that's fine, as is g . h does not enclose F , but then, h is within g , so the specialization is within g too, which technically makes this fine. However, by this reasoning, you can specialize a template absolutely everywhere, because you're always in inside the global namespace, which encloses everything. So I'm pretty sure GCC's behavior here is too permissive, and a bug. You should try this with other compilers too and then file a bug, or possibly a defect report against the standard.

In:

template <> N F<int>::n_s{X::k};      // fails on "‘X’ not declared"

It fails because the namespace associated with F<int>::n_s is g , whereas X is declared in g::h . This is why you need to spell it out like h::F<int>::n_s .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM