Constant string as template arg

M

Marcel Müller

Hi,

from time to time I used something like
template <int I> class_or_function ...
This works fine.

Today I had the first case where
template <const char* C> foo();
...
foo<"LST">();
would be useful. Unfortunately the compiler dislikes it:
error: string literal "LST" is not a valid template argument because
it is the address of an object with static linkage

Why is this not allowed? The address of a static object is a constant.

And with this restriction I could never pass any string as template
argument, or die I miss something?


Marcel
 
J

Johannes Schaub (litb)

Marcel said:
Hi,

from time to time I used something like
template <int I> class_or_function ...
This works fine.

Today I had the first case where
template <const char* C> foo();
...
foo<"LST">();
would be useful. Unfortunately the compiler dislikes it:
error: string literal "LST" is not a valid template argument because
it is the address of an object with static linkage

Why is this not allowed? The address of a static object is a constant.

And with this restriction I could never pass any string as template
argument, or die I miss something?

It's probably less useful than it appears to you at first glance. Specifying
foo<"LST"> would, if it would be allowed, specify the type with *that*
string literal object as argument. Since the standard does not require all
string literals that have the same value to be the same object, when you
later specify foo<"LST"> a second time you have no guarantee that you denote
the same type.
 
A

Alf P. Steinbach /Usenet

* Marcel Müller, on 25.09.2010 15:23:
Hi,

from time to time I used something like
template <int I> class_or_function ...
This works fine.

Today I had the first case where
template <const char* C> foo();
...
foo<"LST">();
would be useful. Unfortunately the compiler dislikes it:
error: string literal "LST" is not a valid template argument
because it is the address of an object with static linkage

Why is this not allowed?

I'm not sure. But it's the same as with a function pointer as template
parameter. It must be a function with external linkage.

Perhaps it's just historical.

It's not a big deal to rewrite the code manually to get the desired effect, and
since the compiler could do that automagically I can't see any technical reason.

The address of a static object is a constant.

And with this restriction I could never pass any string as
template argument, or die I miss something?

You'll have to name the string, like

namespace {
extern char const blah[] = "LST";
}

//...
foo<blah>();

I think that should work.

Check it out.


Cheers & hth.,

- Alf
 
J

Juha Nieminen

Alf P. Steinbach /Usenet said:
Perhaps it's just historical.

I'm not completely sure that's the whole explanation. How should a
compiler compile something like the following?

// Header:
template<const char*> class Foo { /* ... */ };
typedef Foo<"abc"> SomeFoo;

// Compilation unit 1:
SomeFoo foo1;

// Compilation unit 2:
SomeFoo foo2;


I think the compiler would have hard time figuring out what to do with
that "abc" literal in that typedef in different compilation units.
 
M

Marcel Müller

Alf said:
I'm not sure. But it's the same as with a function pointer as template
parameter. It must be a function with external linkage.
You'll have to name the string, like

namespace {
extern char const blah[] = "LST";
}

//...
foo<blah>();

I think that should work.

You are right. That did the trick.

Seems that I read the error message not careful enough. I only
recognized "static" rather than "static linkage".


Marcel
 
A

Alf P. Steinbach /Usenet

* Juha Nieminen, on 26.09.2010 09:17:
I'm not completely sure that's the whole explanation. How should a
compiler compile something like the following?

// Header:
template<const char*> class Foo { /* ... */ };
typedef Foo<"abc"> SomeFoo;

// Compilation unit 1:
SomeFoo foo1;

// Compilation unit 2:
SomeFoo foo2;


I think the compiler would have hard time figuring out what to do with
that "abc" literal in that typedef in different compilation units.

No, it's the same as if you provide the header text directly in each separately
compiled file.


Cheers & hth.,

- Alf
 
J

Juha Nieminen

Alf P. Steinbach /Usenet said:
* Juha Nieminen, on 26.09.2010 09:17:

No, it's the same as if you provide the header text directly in each separately
compiled file.

In other words, you probably get two distinct template instantiations
of Foo which don't share anything (for example, if Foo had static members,
they would not be shared by these two distinct template instantiations)
even though one would think that they should, especially if the exact
same 'SomeFoo' type is used in both compilation units.

This in contrast to the case where the template parameter would be an
integral type, so you would have something like:

template<int> class Foo { /* ... */ };
typedef Foo<5> SomeFoo;

in which case any usage of 'SomeFoo' would share the one and same template
instantiation type.
 
A

Alf P. Steinbach /Usenet

* Juha Nieminen, on 26.09.2010 17:02:
In other words, you probably get two distinct template instantiations
of Foo which don't share anything (for example, if Foo had static members,
they would not be shared by these two distinct template instantiations)

Well, no, not necessarily. It's one possibility. But we're now discussing a
hypothetical language and the effect would depend on that hypothetical
language's rules.

For example, the rules could require constant folding for literals used as
actual template parameters (it's easy to implement since it's easy to rewrite to
do that, e.g. name mangling based on the arg value) -- or the opposite, or
perhaps implementation defined effect.

As I see it there's no way to say what the rules "probably" would be, but no
matter which reasonable rules were chosen I can see no technical reason why it's
not allowed, so I think it's historical.

even though one would think that they should, especially if the exact
same 'SomeFoo' type is used in both compilation units.

Then it seems that you're advocating a different rule than the one you thought
would "probably" be chosen.

If this argument is strong (and I think I agree that it is), wouldn't the rule
implied by that argument then be more probable?

I think so. ;-)

This in contrast to the case where the template parameter would be an
integral type, so you would have something like:

template<int> class Foo { /* ... */ };
typedef Foo<5> SomeFoo;

in which case any usage of 'SomeFoo' would share the one and same template
instantiation type.


Cheers & hth.,

- Alf
 
J

James Kanze

* Marcel Müller, on 25.09.2010 15:23:
I'm not sure. But it's the same as with a function pointer as
template parameter. It must be a function with external
linkage.
Perhaps it's just historical.

In this case, there are two reasons. The first, that a template
argument must have external linkage, probably is just historical
(but I'm not sure that the restriction is going to be removed in
the next version of the standard---I'd have to check). The
second is because whether two repetitions of "LST" are two
different objects (and thus two different instantiations of the
template) or just one is not specified, so even allowing it
wouldn't make it usable.
It's not a big deal to rewrite the code manually to get the
desired effect, and since the compiler could do that
automagically I can't see any technical reason.
You'll have to name the string, like
namespace {
extern char const blah[] = "LST";
}
//...
foo<blah>();

I think that should work.

It does, at least with the compilers we use. Sort of---you do
have to work around the usual Microsoft bugs. (In this case,
I have the equivalent of:

class Base
{
protected:
Base(char const* name) { Saves name, for future use...}
};

template<char const* id>
class Derived : public Base
{
public:
Derived() : Base(id) {}
};

and the constructor of Base gets some random value, rather than
what it should get.
 

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,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top