Search code examples
c++templatesdependent-name

method, that accesses a conditional class member, does not compile only when being invoked


i wrote the following class that has a conditional member _s and worksOnlyForString method that accesses the member as std::string. if worksOnlyForString method is not invoked the code compiles even if the member is not std::string.

there is a well-known c++ rule - a template function is fully compiled only when being used. But in my case, the conditional member triggers this behavior.

The question is - why the code compiles.

#include <iostream>
#include <string>
#include <type_traits>

template<bool isString>
struct S
{
    void worksAlways()
    {
        std::cout << _s;
    }

    // compiles for isString == false. (if not used)
    // but why
    void worksOnlyForString()
    {
        std::cout<<_s.size();
    }


    std::conditional_t<isString, std::string, int> _s;
#if 0 
    //this part does not compile and it is expected and ok
    void checkUnconditionalMember()
    {
        std::cout<<_i.size();
    }
    int _i;
#endif    
};

int main()
{
    S<true> s;
    s._s = "xxx";
    s.worksOnlyForString(); // ok prints "3"

    S<false> s1; // why does this line compile ?
    s1._s = 99;
    s1.worksAlways(); // ok prints "99"

    return 0;
}

Solution

  • The following code is not name dependant, so compiler spot error.

    void checkUnconditionalMember()
    {
        std::cout<<_i.size();
    }
    

    In

    std::conditional_t<isString, std::string, int> _s;
    
    void worksOnlyForString()
    {
        std::cout << _s.size();
    }
    
    • _s is name dependent (depends of isString).
    • and so for std::cout << _s.size();.

    So full check is only done when the function is instantiated.

    Instantiating the class doesn't instantiate each method.