Constant string as template arg

Discussion in 'C++' started by Marcel Müller, Sep 25, 2010.

  1. 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
     
    Marcel Müller, Sep 25, 2010
    #1
    1. Advertising

  2. Marcel Müller wrote:

    > 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.
     
    Johannes Schaub (litb), Sep 25, 2010
    #2
    1. Advertising

  3. * 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

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Sep 25, 2010
    #3
  4. Alf P. Steinbach /Usenet <> wrote:
    > 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.
     
    Juha Nieminen, Sep 26, 2010
    #4
  5. Alf P. Steinbach /Usenet wrote:
    > 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
     
    Marcel Müller, Sep 26, 2010
    #5
  6. * Juha Nieminen, on 26.09.2010 09:17:
    > Alf P. Steinbach /Usenet<> wrote:
    >> 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.


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


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Sep 26, 2010
    #6
  7. Alf P. Steinbach /Usenet <> wrote:
    > * Juha Nieminen, on 26.09.2010 09:17:
    >> Alf P. Steinbach /Usenet<> wrote:
    >>> 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.

    >
    > 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.
     
    Juha Nieminen, Sep 26, 2010
    #7
  8. * Juha Nieminen, on 26.09.2010 17:02:
    > Alf P. Steinbach /Usenet<> wrote:
    >> * Juha Nieminen, on 26.09.2010 09:17:
    >>> Alf P. Steinbach /Usenet<> wrote:
    >>>> 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.

    >>
    >> 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)


    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

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Sep 26, 2010
    #8
  9. Marcel Müller

    James Kanze Guest

    On Sep 25, 2:56 pm, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > wrote:
    > * Marcel Müller, on 25.09.2010 15:23:


    > > 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.


    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.


    > > 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.


    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.

    --
    James Kanze
     
    James Kanze, Sep 27, 2010
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. n00m
    Replies:
    5
    Views:
    412
  2. Tuka Opaleye
    Replies:
    2
    Views:
    158
    Tuka Opaleye
    Mar 29, 2008
  3. jonnytheclown

    How to tell if a subroutine arg is a constant

    jonnytheclown, Feb 24, 2005, in forum: Perl Misc
    Replies:
    9
    Views:
    157
    Brian McCauley
    Mar 1, 2005
  4. Replies:
    7
    Views:
    203
  5. Replies:
    21
    Views:
    420
    Barry Schwarz
    Mar 5, 2014
Loading...

Share This Page