d43d2832   
   From: crusader.mike@googlemail.com   
      
   On Oct 24, 1:48 pm, fmatthew5876 wrote:   
   > If what you really want is the equivalent of this:   
   > char const S1[] = "FOO";   
   > char const S2[] = "FOO";   
   > then without being able to make "FOO" a #define, the only option I   
   > can think of is to write an external script into your build system   
   > that parses the file that contains S1 and writes it onto the   
   > initializer for S2.   
   >   
   > They still might not be collapsed at link time. Especially if S1 is   
   > located in a shared library.   
      
      
   Thank you (and everybody else) for answers. I'll follow suggestion   
   received in personal email and try to explain the problem I was trying   
   to solve instead of boiling it down to bare minimum. You might find it   
   more interesting:   
      
   Given:   
   - bunch of arrays declared elsewhere (outside of my control):   
    char const S1[] = "ABC";   
    char const S2[] = "DEF";   
      
   - template that looks like this:   
    template class Value   
    {   
    ... // quite a bit of logic is in these dots   
    static char const* TAG;   
    };   
      
   every instance of this template has a declaration like this (in some   
   translation unit):   
    template<> char const* Value::TAG = "int";   
   some of them look like this:   
    template<> char const* Value::TAG = S1;   
      
   Needed:   
      
   - to convert TAG from pointer to array, i.e. solution should look smth   
   like:   
    // .h   
    template class Value   
    {   
    ...   
    static char const TAG[]; // note that array size is not   
    // associated with variable yet   
    };   
      
    // strangely enough compiler treats these declarations as typical   
    // "extern char const S[N]" and associates array length (e.g.   
    // sizeof(S1)) with given variable instance (e.g. Value::TAG)   
    template<> char const Value::TAG[sizeof("int")];   
    template<> char const Value::TAG[sizeof(S1)];   
      
    // after this point all users could see array size   
    // (i.e. could use sizeof)   
      
    // .cpp   
    // this works fine   
    template<> char const Value::TAG[sizeof("int")] = "int";   
    // this doesn't compile :-\   
    template<> char const Value::TAG[sizeof(S1)] = S1;   
      
   I am aware that this code tries to create new array instance (i.e.   
   we'll end up with a copy of the same S1 string in two different   
   translation units) -- this is fine, because I know my linker will   
   collapse them into one later (no shared libs).   
      
   In any case code above does not work. After I've replaced array with a   
   reference to array, I've discovered that forward declarations used to   
   "add" array size info to variable stopped working -- compiler refuses   
   to accept them (same for stuff in .cpp -- now it complains about   
   difference between 'reference to array[]' vs 'reference to array[8]',   
   even though it was totally cool with 'array[]' vs 'array[8]').   
      
   I ended up working this around via extra template class -- trait for   
   TAG, which users are supposed to specialize and provide array size   
   info early. I.e. I ended up with following (imho) ugly solution:   
      
    // .h   
    template class DefTrait {   
    // main template is empty, possible specializations are:   
    // static char const TAG[sizeof("test")] = "test";   
    // static char const (&TAG)[sizeof(S1)] = S1;   
    }   
      
    template class TagTrait = DefTrait>   
    class Value   
    {   
    ...   
    static char const (&TAG)[sizeof(TagTrait::TAG)];   
    };   
      
    template class TagTrait> class Value   
    char const (&Value::TAG)   
   [sizeof(TagTrait::TAG)] = TagTrait::TAG;   
      
   Now, after I've read answers to my original post I've realized that   
   removing Value::TAG and instead inheriting Value from TagTrait class   
   is better. Smth like:   
      
    // .h   
    template class ValueTag { static char const TAG[0]; }   
      
    // if necessary ValueTag can be added to template parameters later   
    template class Value : public ValueTag { ... };   
      
    template<> class ValueTag { static char const   
   TAG[sizeof("bool")]; }   
    Value typedef ValueBool;   
      
    template<> class ValueTag { static char const (&TAG)   
   [sizeof(S1)]; }   
    Value typedef ValueS1;   
      
    // .cpp   
    char const ValueTag::TAG[sizeof("bool")] = "bool";   
    char const (&ValueTag::TAG)[sizeof(S1)] = S1;   
      
   I'll wrap it into macros for convenience. Array length is always   
   specified to reduce chance of dumb mistake that looks like this (my   
   programs needs a guarantee that these char arrays contain exactly one   
   null byte exactly at 'sizeof(S1) - 1' position):   
      
    // .h   
    extern char const S1[sizeof("ABCD")];   
      
    // .cpp   
    char const S1[] = "ACD"; // S1 is [ACD\0\0]   
      
   Still, it is an omission in C++ -- why I can have this:   
      
    char const S1 = 'A';   
    char const S2 = S2;   
      
    or this:   
      
    char const S1[] = "AB";   
    char const S2[] = { S1[0], S1[1], S1[2] };   
      
   but cannot have this:   
      
    char const S1[] = "AB";   
    char const S2[] = S1;   
   ?   
      
   There is nothing that prevents language from allowing such construct   
   -- all info needed by compiler is there...   
      
   Regards,   
   Michael.   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|