samedi 1 juin 2019

Trouble understanding C++ dependent types, vs what's on the current instantiation

The code below is adapted from the answer here: https://stackoverflow.com/a/17579889/352552

My purpose in asking this question is try to to understand better how C++ handles type resolution around dependent types, versus what's considered to be on the current instantiation, and therefore not needing a typename qualifier. I've been getting contradictory results from different compilers, so I've come here looking for a more canonical answer.

Consider this code

#include <iostream>

struct B {
  typedef int result_type;
};

template<typename T>
struct C {
};

template<>
struct C<float> {
    typedef float result_type;
}; 

template<typename T>
struct D : B, C<T> {
  std::string show() {
    //A) Default to current instantiation - ignore dependent type, even if one exists, or so I hope
    D::result_type r1;

    //B) What **exactly** does typename add, here?
    //typename D::result_type r1;

    return whichType(r1);
  }

  std::string whichType (int val){
    return "INT";
  }
  std::string whichType (float val){
    return "FLOAT";
  }    
};


int main() {  
  D<std::string> stringD;
  D<float> floatD;
  std::cout<<"String initialization "<<stringD.show()<<std::endl;
  std::cout<<"Float initialization "<<floatD.show()<<std::endl;
}

line A) in show(), if I understand correctly, tells the compiler to use the current instantiation, so I should get INT INT. On GCC, I do. Cool.

Line B, again if understand correctly, should either tell the compiler to consider dependent types, which would make that line error out because of the ambiguity; or, if that means only consider dependent types, I should get INT FLOAT. On GCC I get INT INT there, too. Why?


Running this on Clang.

Line A doesn't compile at all.

error: no type named 'result_type' in 'D'; did you mean simply 'result_type'? D::result_type r1;

dropping the D:: does indeed yield INT INT.

Should it have compiled, or is Clang incorrect here?

Line B does indeed error on the ambiguity

error: member 'result_type' found in multiple base classes of different types typename D::result_type r1


Can anyone here say with authority which compiler (if any!) is canonically correct, and why?

Assuming Clang is correct, it would imply that

MyType::F

is invalid for referencing a type from the current instantiation if it exists on a base type; it's only valid if the type is defined on that class. Ie adding

typedef double dd;

to D

and then

D::dd d = 1.1;
std::cout<<d;

in show would work just fine, which is indeed the case.

Moreover,

typename D::sometype

means to consider dependent types, but not exclusively, and so expect errors if such a type winds up defined in multiple places, either in the current instantiation, and or dependent on a template parameter.


Link to GCC repl I was using: https://wandbox.org/

Link to Clang repl I was using: https://repl.it/languages/cpp11

Aucun commentaire:

Enregistrer un commentaire