Strings as non-type template parameters

Discussion in 'C++' started by Rennie deGraaf, May 31, 2010.

  1. Hello,

    What are the rules concerning how to use a string as a template
    parameter? I assume that the reason why it is necessary to use a named
    object rather than a string literal is that the compiler needs to be
    able to convert the value into an integer (or something similar), but I
    haven't been able to make any sense about how it handles extern and const.

    For instance, consider the following code:

    typedef const wchar_t Bar[];
    //typedef wchar_t Bar[];
    //typedef const wchar_t* Bar;
    //typedef const wchar_t* const Bar;

    extern Bar bar = L"bar";
    //Bar bar = L"bar";

    template <Bar>
    struct Foo {};

    Foo<bar> foo;

    int main()
    {
    return 0;
    }

    When using the first definition of Bar (as a const array) and the first
    definition of bar (as extern), it compiles*. When Bar is non-const (the
    second definition), then it compiles whether or not bar is extern
    (although I get a warning if it /is/ extern). But when I use const and
    /not/ extern, it doesn't compile. Why?

    Also, why won't it work when I declare Bar as a pointer rather than an
    array? I must admit to never having entirely understood the difference
    between the two forms of declaration.

    Incidentally, why can't I typedef Bar as "extern const wchar_t Bar[]"?

    Thanks,
    Rennie

    * using either GCC 4.4.1 or Microsoft Visual Studio 2008
    Rennie deGraaf, May 31, 2010
    #1
    1. Advertising

  2. Rennie deGraaf

    Ian Collins Guest

    On 05/31/10 02:48 PM, Rennie deGraaf wrote:
    > Hello,
    >
    > What are the rules concerning how to use a string as a template
    > parameter? I assume that the reason why it is necessary to use a named
    > object rather than a string literal is that the compiler needs to be
    > able to convert the value into an integer (or something similar), but I
    > haven't been able to make any sense about how it handles extern and const.
    >
    > For instance, consider the following code:
    >
    > typedef const wchar_t Bar[];
    > //typedef wchar_t Bar[];
    > //typedef const wchar_t* Bar;
    > //typedef const wchar_t* const Bar;
    >
    > extern Bar bar = L"bar";
    > //Bar bar = L"bar";
    >
    > template<Bar>
    > struct Foo {};
    >
    > Foo<bar> foo;
    >
    > int main()
    > {
    > return 0;
    > }
    >
    > When using the first definition of Bar (as a const array) and the first
    > definition of bar (as extern), it compiles*. When Bar is non-const (the
    > second definition), then it compiles whether or not bar is extern
    > (although I get a warning if it /is/ extern). But when I use const and
    > /not/ extern, it doesn't compile. Why?


    Linkage?

    extern consts have global linkage, while non-const have local linkage.

    > Also, why won't it work when I declare Bar as a pointer rather than an
    > array? I must admit to never having entirely understood the difference
    > between the two forms of declaration.


    The gcc warning is enlightening:

    /tmp/y.cc:13: error: 'bar' is not a valid template argument because
    'bar' is a variable, not the address of a variable

    > Incidentally, why can't I typedef Bar as "extern const wchar_t Bar[]"?


    I don't think linkage specifications can be part of a typedef. An
    object has linkage, not a type.

    --
    Ian Collins
    Ian Collins, May 31, 2010
    #2
    1. Advertising

  3. On 05/30/2010 08:23 PM, Ian Collins wrote:
    > On 05/31/10 02:48 PM, Rennie deGraaf wrote:
    >> Hello,
    >>
    >> What are the rules concerning how to use a string as a template
    >> parameter? I assume that the reason why it is necessary to use a named
    >> object rather than a string literal is that the compiler needs to be
    >> able to convert the value into an integer (or something similar), but I
    >> haven't been able to make any sense about how it handles extern and
    >> const.
    >>
    >> For instance, consider the following code:
    >>
    >> typedef const wchar_t Bar[];
    >> //typedef wchar_t Bar[];
    >> //typedef const wchar_t* Bar;
    >> //typedef const wchar_t* const Bar;
    >>
    >> extern Bar bar = L"bar";
    >> //Bar bar = L"bar";
    >>
    >> template<Bar>
    >> struct Foo {};
    >>
    >> Foo<bar> foo;
    >>
    >> int main()
    >> {
    >> return 0;
    >> }
    >>
    >> When using the first definition of Bar (as a const array) and the first
    >> definition of bar (as extern), it compiles*. When Bar is non-const (the
    >> second definition), then it compiles whether or not bar is extern
    >> (although I get a warning if it /is/ extern). But when I use const and
    >> /not/ extern, it doesn't compile. Why?

    >
    > Linkage?
    >
    > extern consts have global linkage, while non-const have local linkage.


    I've found statements on the web claiming that to use a named object as
    a template parameter, it must have external linkage. Why is this
    important? And is there a difference between the linkage of "wchar_t
    bar[]" and "const wchar_t bar[]"?

    >> Also, why won't it work when I declare Bar as a pointer rather than an
    >> array? I must admit to never having entirely understood the difference
    >> between the two forms of declaration.

    >
    > The gcc warning is enlightening:
    >
    > /tmp/y.cc:13: error: 'bar' is not a valid template argument because
    > 'bar' is a variable, not the address of a variable


    Why is that a problem when bar is defined as a pointer, but not when
    defined as an array? If I use the pointer definition, then using "&bar"
    as my template parameter would use the address of the pointer, not the
    address of the string. (Not to mention that that would be a wchar_t**,
    not a wchar_t*.) Is there some actual difference between "wchar_t* bar"
    and "wchar_t bar[]" in this scenario, unlike most others?
    Rennie deGraaf, May 31, 2010
    #3
  4. Rennie deGraaf

    Jonathan Lee Guest

    On May 31, 9:54 am, Victor Bazarov <> wrote:
    > No.  Both 'bar' have external linkage.  "An array of blah" does not
    > really differ from "an array of constant blah".  It's only for the
    > compiler, so that individual elements of the latter array could not be
    > changed (or passed by a ref to non-const, and so on).


    A question for clarification: a single const object has internal
    linkage, but arrays of const values don't?

    --Jonathan
    Jonathan Lee, May 31, 2010
    #4
  5. On 5/31/2010 10:27 AM, Jonathan Lee wrote:
    > On May 31, 9:54 am, Victor Bazarov<> wrote:
    >> No. Both 'bar' have external linkage. "An array of blah" does not
    >> really differ from "an array of constant blah". It's only for the
    >> compiler, so that individual elements of the latter array could not be
    >> changed (or passed by a ref to non-const, and so on).

    >
    > A question for clarification: a single const object has internal
    > linkage, but arrays of const values don't?


    My mistake. Arrays of cv-qualified T have internal linkage unless
    specified otherwise. Since arrays themselves cannot be cv-qualified
    (they aren't really objects), they derive their cv-qualification from
    the elements. 8.3.4 explains.

    I blame my mistake on all the Quebec smoke in our atmosphere. :)

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, May 31, 2010
    #5
  6. Rennie deGraaf

    James Kanze Guest

    On May 31, 3:48 am, Rennie deGraaf <>
    wrote:

    > What are the rules concerning how to use a string as a template
    > parameter?


    You can't use any class type as a template parameter.

    > I assume that the reason why it is necessary to use a named
    > object rather than a string literal is that the compiler needs
    > to be able to convert the value into an integer (or something
    > similar), but I haven't been able to make any sense about how
    > it handles extern and const.


    String literals aren't strings:). You can't use a string
    literal because it doesn't have linkage; the standard requires
    template parameters to have external linkage.

    > For instance, consider the following code:


    > typedef const wchar_t Bar[];
    > //typedef wchar_t Bar[];
    > //typedef const wchar_t* Bar;
    > //typedef const wchar_t* const Bar;


    Forget the typedef. In this case, they only cause confusion.

    > extern Bar bar = L"bar";
    > //Bar bar = L"bar";


    extern wchar_t const bar[] = L"bar";

    Or without the const.

    The template argument should be "wchar_t const*".

    > template <Bar>
    > struct Foo {};


    > Foo<bar> foo;


    > int main()
    > {
    > return 0;
    > }


    > When using the first definition of Bar (as a const array) and
    > the first definition of bar (as extern), it compiles*. When
    > Bar is non-const (the second definition), then it compiles
    > whether or not bar is extern (although I get a warning if it
    > /is/ extern). But when I use const and /not/ extern, it
    > doesn't compile. Why?


    Because const objects default to internal linkage, and template
    arguments must have external linkage.

    > Also, why won't it work when I declare Bar as a pointer rather
    > than an array?


    Not having access to the definition of Foo, I can't be sure; if
    you want to instantiate Foo with a pointer, you have to declare
    Foo to use a reference to a pointer, or provide a pointer which
    is a compile time constant (to something with external linkage).

    > I must admit to never having entirely understood the difference
    > between the two forms of declaration.


    Which two forms?

    > Incidentally, why can't I typedef Bar as "extern const wchar_t
    > Bar[]"?


    Because "extern" is not part of a type. It's a storage class
    specifiers. A typedef can only be used with type specifiers.

    --
    James Kanze
    James Kanze, Jun 1, 2010
    #6
  7. Rennie deGraaf

    James Kanze Guest

    On May 31, 4:23 am, Ian Collins <> wrote:
    > On 05/31/10 02:48 PM, Rennie deGraaf wrote:


    [...]
    > extern consts have global linkage, while non-const have local linkage.

    ^^^^^^^^^
    You mean "non-extern const", don't you?

    --
    James Kanze
    James Kanze, Jun 1, 2010
    #7
  8. Rennie deGraaf

    James Kanze Guest

    On May 31, 9:04 am, Rennie deGraaf <>
    wrote:
    > On 05/30/2010 08:23 PM, Ian Collins wrote:
    > > On 05/31/10 02:48 PM, Rennie deGraaf wrote:


    [...]
    > I've found statements on the web claiming that to use a named
    > object as a template parameter, it must have external linkage.
    > Why is this important?


    Because the standard says so. Partially, at least, because it
    wasn't too sure how to implement templates for objects without
    external linkage.

    The latter is especially true in the case of string literals,
    since it is unspecified whether "bar" has the same address or
    not in two different translation units.

    > And is there a difference between the linkage of "wchar_t
    > bar[]" and "const wchar_t bar[]"?


    Yes. For histerical^h^h^h^h^h^horical reasons, an object
    defined at namespace scope has internal linkage if it is const,
    external otherwise.

    Note that this only depends on the const-ness of the object
    itself. If the object is a pointer, the const-ness of what is
    pointed to has no effect. In other words, both
    char const* p;
    and
    char* p;
    have external linkage.

    And finally, the rule only applies to "objects". A reference
    defined at namespace scope has external linkage, even though it
    is always "const". (As far as I know, there is no way of giving
    a reference internal scope.)

    > >> Also, why won't it work when I declare Bar as a pointer
    > >> rather than an array? I must admit to never having
    > >> entirely understood the difference between the two forms of
    > >> declaration.


    > > The gcc warning is enlightening:


    > > /tmp/y.cc:13: error: 'bar' is not a valid template argument because
    > > 'bar' is a variable, not the address of a variable


    > Why is that a problem when bar is defined as a pointer, but not when
    > defined as an array?


    Because a pointer is a variable, not a compile time constant.

    > If I use the pointer definition, then using "&bar" as my
    > template parameter would use the address of the pointer, not
    > the address of the string. (Not to mention that that would be
    > a wchar_t**, not a wchar_t*.) Is there some actual difference
    > between "wchar_t* bar" and "wchar_t bar[]" in this scenario,
    > unlike most others?


    There are practically no scenarios where there isn't a
    difference. Pointers and arrays are two completely different,
    and largely unrelated things.

    --
    James Kanze
    James Kanze, Jun 1, 2010
    #8
  9. Rennie deGraaf

    Ian Collins Guest

    On 06/ 1/10 09:25 PM, James Kanze wrote:
    > On May 31, 4:23 am, Ian Collins<> wrote:
    >> On 05/31/10 02:48 PM, Rennie deGraaf wrote:

    >
    > [...]
    >> extern consts have global linkage, while non-const have local linkage.

    > ^^^^^^^^^
    > You mean "non-extern const", don't you?


    Yes, I did.

    --
    Ian Collins
    Ian Collins, Jun 1, 2010
    #9
  10. On 06/01/2010 02:36 AM, James Kanze wrote:
    > On May 31, 9:04 am, Rennie deGraaf <>


    >> If I use the pointer definition, then using "&bar" as my
    >> template parameter would use the address of the pointer, not
    >> the address of the string. (Not to mention that that would be
    >> a wchar_t**, not a wchar_t*.) Is there some actual difference
    >> between "wchar_t* bar" and "wchar_t bar[]" in this scenario,
    >> unlike most others?

    >
    > There are practically no scenarios where there isn't a
    > difference. Pointers and arrays are two completely different,
    > and largely unrelated things.


    Semantically, they are different and largely unrelated things.
    Syntactically, they are relatively few situations in which an array
    differs from a pointer to an array.
    Rennie deGraaf, Jun 3, 2010
    #10
  11. Rennie deGraaf

    James Kanze Guest

    On Jun 3, 8:03 am, Rennie deGraaf <>
    wrote:
    > On 06/01/2010 02:36 AM, James Kanze wrote:


    > > On May 31, 9:04 am, Rennie deGraaf <>
    > >> If I use the pointer definition, then using "&bar" as my
    > >> template parameter would use the address of the pointer,
    > >> not the address of the string. (Not to mention that that
    > >> would be a wchar_t**, not a wchar_t*.) Is there some
    > >> actual difference between "wchar_t* bar" and "wchar_t
    > >> bar[]" in this scenario, unlike most others?


    > > There are practically no scenarios where there isn't a
    > > difference. Pointers and arrays are two completely
    > > different, and largely unrelated things.


    > Semantically, they are different and largely unrelated things.
    > Syntactically, they are relatively few situations in which an
    > array differs from a pointer to an array.


    Syntactically, the name of an array and the name of a pointer
    are both symbols. And the syntax stops there. The rest is
    semantics, and the two are fondamentally unrelated.

    --
    James Kanze
    James Kanze, Jun 3, 2010
    #11
  12. Rennie deGraaf

    James Kanze Guest

    On Jun 3, 8:03 pm, I V <> wrote:
    > On Thu, 03 Jun 2010 00:03:29 -0700, Rennie deGraaf wrote:
    > > Semantically, they are different and largely unrelated
    > > things. Syntactically, they are relatively few situations
    > > in which an array differs from a pointer to an array.


    > I think that's because almost all operations on an array
    > involve the implicit conversion of the array to a pointer.
    > Indeed, I'm trying to think what operations are possible on an
    > array (as opposed to the pointer that it converts to). The
    > only one I can think of is passing the array to a function.


    The most obvious one is using an array as an operand of sizeof.
    Also, of course, using it to initialize a reference. And the
    most fundamental: what the definition defines.

    --
    James Kanze
    James Kanze, Jun 3, 2010
    #12
    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. Sebastian Faust
    Replies:
    4
    Views:
    411
    Sebastian Faust
    Oct 18, 2003
  2. CoolPint
    Replies:
    2
    Views:
    363
    Ivan Vecerina
    Nov 8, 2003
  3. aravindap
    Replies:
    2
    Views:
    368
    aravindap
    Oct 24, 2008
  4. Replies:
    4
    Views:
    516
    Noah Roberts
    Feb 10, 2009
  5. kito
    Replies:
    2
    Views:
    413
Loading...

Share This Page