Thursday, May 30, 2019

c++11 - 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 


struct B {
typedef int result_type;
};

template
struct C {
};

template<>
struct C {

typedef float result_type;
};

template
struct D : B, C {
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 stringD;
D floatD;
std::cout<<"String initialization "< std::cout<<"Float initialization "<}



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. So far, so good.



Line B, again if I 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 correct 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 might 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<


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



Moreover,




typename D::sometype



seems to mean 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.



But again, this all assumes Clang's behavior is correct according to spec, which I can't speak to.






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




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

No comments:

Post a Comment

plot explanation - Why did Peaches&#39; mom hang on the tree? - Movies &amp; TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...