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;
}
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
).std::cout << _s.size();
.So full check is only done when the function is instantiated.
Instantiating the class doesn't instantiate each method.