1

I wrote this code circa '08 using gcc 3.x. I'm now trying to compile with clang 3.4 and I'm getting a template error that I don't understand. The idea is to declare fixed-dimension vec types of arbitrary dimension and precision, and then define vecPair types based on those. I do not understand how the usage of the template typename S inside of "a.convert()" is shadowing the template parameter; it is meant to use the parameter, not redeclare it. Any information would be greatly appreciated!

typedef unsigned int Uns;

template <typename T>
inline const T& min(const T& a, const T& b) {
  return a <= b ? a : b;
}

template <Uns N, typename T>
struct vec {

  T comp[N];

  template <Uns M, typename S>
  inline vec<M, S> convert() const {
    vec<M, S> converted;
    for (Uns i = 0; i < min(M, N); ++i) converted[i] = comp[i];
    for (Uns i = N; i < M; ++i) converted[i] = 0;
    return converted;
  }
};

template <Uns N, typename T>
struct vecPair {

  vec<N, T> a;
  vec<N, T> b;

  inline vecPair(const vec<N, T>& _a, const vec<N, T>& _b) : a(_a), b(_b) {}

  template <Uns M, typename S>
  inline vecPair<M, S> convert() const {
    vec<M, S> ca = a.convert<M, S>();
    vec<M, S> cb = b.convert<M, S>();
    return vecPair<M, S>(ca, cb);
  }
};

clang 3.4 gives the following output:

$ clang++ -fsyntax-only vec-bug.cpp 
vec-bug.cpp:30:33: error: declaration of 'S' shadows template parameter
    vec<M, S> ca = a.convert<M, S>();
                                ^
vec-bug.cpp:28:29: note: template parameter is declared here
  template <Uns M, typename S>
                            ^
vec-bug.cpp:30:34: error: expected ';' at end of declaration
    vec<M, S> ca = a.convert<M, S>();
                                 ^
                                 ;
vec-bug.cpp:31:12: error: template argument for template type parameter must be a type
    vec<M, S> cb = b.convert<M, S>();
           ^
vec-bug.cpp:11:27: note: template parameter is declared here
template <Uns N, typename T>
                          ^
...
gwk
  • 638
  • 7
  • 15
  • Well, I duplicated. `G++` and `VC++` give no warnings or errors, `clang++` gives the warnings listed. I'm stumped. – Mooing Duck Feb 27 '14 at 00:42
  • I think this is an SSCCE: http://ideone.com/bieydI. It appears that clang is parsing this is as `a.convert()` separated by a comma operator. Now I'm no longer sure that clang is wrong. It may be that G++ and VC++ are technically in the wrong here, not sure. – Mooing Duck Feb 27 '14 at 00:49

1 Answers1

3

This seems to work:

vec<M, S> ca = a.template convert<M, S>();
vec<M, S> cb = b.template convert<M, S>();

I think that a and b have dependent types, and so you need to disambiguate that convert is a template. I'm not sure why GCC doesn't mind.

Update: This seems to be a known GCC bug.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I've never quite figured out when `template` is required like this, and now I'm not sure which compiler(s) are wrong. – Mooing Duck Feb 27 '14 at 00:50
  • @MooingDuck: It seems mildly straight-forward: You don't know what the type of `a` is, so you don't know whether it has a member called `convert`, and whether that member is a value, a type or a template. (Bear in mind that `vec` can be specialized.) – Kerrek SB Feb 27 '14 at 00:51
  • 1
    @MooingDuck: Full rules in 14.6.2.2, which I just checked, but I'm not completely clear what "unknown specialization" means in that context. I'm leaning towards Clang being right about this, though. (Especially 14.6.2.2/5 seems to describe the present situation quite well.) – Kerrek SB Feb 27 '14 at 00:52