3

While recently migrating older code (with permissive-), I found one small item that I didn't expect. The derived class could no longer access a protected variable without fully qualifying the name. Consider this very contrived example:

// CVTW == contrived value type wrapper
template<typename VALUE_TYPE>
class CVTW
{
public:
    explicit CVTW(VALUE_TYPE const value) : _value { value }
    { }

protected:
    VALUE_TYPE _value;  // <-- target in question
};
// .  .  .  .  .  .  .  .  .  .  .  .  .  .
class IntValueType : public CVTW<int>
{
public:
    using CVTW<int>::CVTW;
    int GetValue() const { return _value; } // <-- compiles
};
// .  .  .  .  .  .  .  .  .  .  .  .  .  .
template<typename VALUE_TYPE>
class CTVW_2 : public CVTW<VALUE_TYPE>
{
    // another solution to successfully access _value directly
    //using CVTW<VALUE_TYPE>::_value;

public:
    using CVTW<VALUE_TYPE>::CVTW;
    VALUE_TYPE GetValue() const
    {
        //return _value;                 // <-- error
        return CVTW<VALUE_TYPE>::_value; // <-- compiles
    }
};
// .  .  .  .  .  .  .  .  .  .  .  .  .  .
int main()
{
    IntValueType v { 1 };
    CTVW_2<int> v2 { 2 };
}

When attempting to access _value from CTVW_2 (without fully qualifying the name or a using statement) the following error is reported:

error: use of undeclared identifier '_value'

I realize this has nothing to do with protected access scope, and I have some understanding of name hiding and the fragile base problem, but in this case, why is this necessary and why is there no error reported when IntValueType accesses the same variable in the same manner?

EDIT: Here is a working example. MSVC isn't as picky, but Clang and GCC report the issue.

Isabelle
  • 73
  • 6
  • 5
    It's a dependent name (more precisely, a name of a member of a dependent base class). You can also say `this->_value`. – Kerrek SB Nov 28 '17 at 17:34
  • 1
    IMHO, this isn't necessarily a C++17 issue (though I'm not sure whether you intended to state this). I realized this even when we were on VS2008 and ported to Linux. (It's probably 4 years ago and I cannot remember what g++ we used then.) IMHO, this happens always when you have template classes derived from something and try to access derived members. As you already told: MSVC is quite lax about certain things. – Scheff's Cat Nov 28 '17 at 17:38
  • @Scheff - I agree, and I didn't mark the question as such. However I noticed older compilers I was using didn't report the issue – Isabelle Nov 28 '17 at 17:41
  • @KerrekSB - Good point. But why is IntValueType able to access the variable directly? And why did older compilers not enforce this? – Isabelle Nov 28 '17 at 17:43
  • 1
    @Isabelle: Because it's not dependent there, on account of `IntValueType` not being a template. – Kerrek SB Nov 28 '17 at 17:44
  • 1
    This is an old deficiency in VC++ that is about to be fixed https://blogs.msdn.microsoft.com/vcblog/2017/09/11/two-phase-name-lookup-support-comes-to-msvc/ – Bo Persson Nov 28 '17 at 17:47
  • @BoPersson - nice catch. – Isabelle Nov 28 '17 at 17:47
  • 1
    @Scheff - I removed the mention of C++17 – Isabelle Nov 28 '17 at 17:51
  • This is a somehow related question from a month ago: [SO: why does g++ need both definitions of template class and its friend function?](https://stackoverflow.com/q/46986853/7478597). – Scheff's Cat Nov 28 '17 at 17:51
  • @BoPersson is right. This is a two-phase name lookup question, and answered well by Steve Jessop. https://stackoverflow.com/questions/4643074/why-do-i-have-to-access-template-base-class-members-through-the-this-pointer/4643295#4643295 – Isabelle Nov 28 '17 at 18:23

0 Answers0