Linker complains about symbol it can't possibly use

O

Old Wolf

I have the following code. One one compiler it compiles OK,
on the other it gives the two warnings shown below, and then
the linker fails because Foo<int>::str is undefined.

Which is correct?

Second question: the compiler won't accept:
static const std::string str = std::string();

Is there any way to achieve that effect with alternative code?

#include <iostream>

template<typename T>
struct Foo
{
static const bool i = false;
static const std::string str;
};

template<typename T>
void foo()
{
std::cout << Foo<T>::str << std::endl;
}

template<typename T>
void bar()
{
if (Foo<T>::i) // "Condition is always false."
foo<T>(); // "Unreachable code."
}

int main()
{
bar<int>();
}
 
L

Larry I Smith

Old said:
I have the following code. One one compiler it compiles OK,
on the other it gives the two warnings shown below, and then
the linker fails because Foo<int>::str is undefined.

Which is correct?

Second question: the compiler won't accept:
static const std::string str = std::string();

Is there any way to achieve that effect with alternative code?

#include <iostream>

template<typename T>
struct Foo
{
static const bool i = false;
static const std::string str;
};

template<typename T>
void foo()
{
std::cout << Foo<T>::str << std::endl;
}

template<typename T>
void bar()
{
if (Foo<T>::i) // "Condition is always false."
foo<T>(); // "Unreachable code."
}

int main()
{
bar<int>();
}

Well, 'i' is always 'false', and can never be anyting else.
You made 'i' 'static const' and initialized it to 'false',
so 'i' can never be changed (it will always be false).

Since 'Foo<T>::i' and 'Foo<T>::str' are both 'static const',
there will be only one 'i' and one 'str' regardless of how
many Foo<T> objects are created. I believe that the 'const'
qualifier means they can never be changed once they are created.

Someone with more knowledge about 'static' and 'const' members
in templates may be able to provide more info.

Regards,
Larry
 
O

Old Wolf

Larry said:
Well, 'i' is always 'false', and can never be anyting else.
You made 'i' 'static const' and initialized it to 'false',
so 'i' can never be changed (it will always be false).

I meant, the warnings are OK but is the link error correct or not?
The purpose of the warnings was to show that Foo<int>::str should
never be used.

Also, my code needs a #include <string> .
 
L

Larry I Smith

Old said:
I meant, the warnings are OK but is the link error correct or not?
The purpose of the warnings was to show that Foo<int>::str should
never be used.

Also, my code needs a #include <string> .

Try the following code. It creates the missing 'str'
and demos some other stuff...

#include <iostream>
#include <string>

template<typename T>
struct Foo
{
// a static of basic type (int, char, etc) can
// be init'd in the template (or not)
static const bool i = false;
static const bool i2;

// static non-basic types must be init'd external
// to the template
static const std::string str;
};

template<typename T>
void foo()
{
std::cout << "Foo<T>::str = "
<< Foo<T>::str
<< ", Foo<T>::i = "
<< Foo<T>::i
<< ", Foo<T>::i2 = "
<< Foo<T>::i2
<< std::endl;
}

template<typename T>
void bar()
{
if (Foo<T>::i) // "Condition is always false."
foo<T>(); // "Unreachable code."
}

// set the values for Foo<int>::str and Foo<int>::i2
const std::string Foo<int>::str("hello");
const bool Foo<int>::i2 = true;

int main()
{
bar<int>();
foo<int>();
}

Regards,
Larry
 
K

kevin.hall

Static constant fundamental types (ints, chars, floats, booleans) are
OK to initialize the way you did. The reason is that the compiler can
substitue the values inline. I believe if you attempted to take the
address of "i", you'd get a similar warning message that it was not
defined either. Class types with constructors and destructors need to
be explicitly declared outside a templete. The reason is that the code
for the object can't be inlined and the compiler needs a place to
initialize the class' data. You did not provide this with "str", thus
the error. I believe non-fundamental PODs would also fail since
compilers have a difficult time inlining them, but I'm not 100% sure
here.

Anyway, as far as why one compiler compiles fine and the other
doesn't.... well, the compiler that produces the error is well within
it rights from the ISO standard to compile the code anyway -- even if
it is unreachable. That's why it produces the linker error. The
compiler that doesn't compile the unreachable code performed an
optimization and that's fine too -- it just means that the linker isn't
looking for the code symbol. So each compiler is within its right.
Personally, I'd like to receive the linker error. It's telling me
something about my code that may be important down the road -- namely
that I need to define the instances. Then in all likelyhood, I would
change where str was defined so I wouldn't have to keep defining new
instances for each possible template arguement.

Anyway, I hope this helps!

- Kevin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top