3

I want to specialize a template for a certain GUID, which is a 16 byte struct. The GUID object has internal linkage, so I can't use the address of the object itself, but I thought I could use the contents of the object, since the object was a constant. But this doesn't work, as illustrated by this example code:

struct S
{
    int const i;
};
S const s = { 42 };
char arr[s.i];

Why isn't s.i a constant if s is? Any workaround?

ruakh
  • 175,680
  • 26
  • 273
  • 307
Bruno Martinez
  • 2,850
  • 2
  • 39
  • 47
  • 2
    Just because `i` is marked as `const` doesn't mean its initialization is also const. – Xeo Mar 13 '13 at 17:41
  • What if you did `S const s = someMethodThatReturnsSomeS();`? – Luchian Grigore Mar 13 '13 at 17:43
  • would the value of `s.i` be the same for each object of the specialized type? because that can be handled pretty easily. also, a but of code from the specialization would be really useful. – Ryan Haining Mar 14 '13 at 02:11
  • @xhainingx I've made a follow up question that describes exactly what I want to achieve here http://stackoverflow.com/questions/15410833/specialize-a-template-for-a-guid-value – Bruno Martinez Mar 14 '13 at 13:37

2 Answers2

7

The initialization of the struct s can happen at run time. However, the size of an array must be known at compile time. The compiler won't (for sure) know that the value of s.i is known at compile time, so it just sees you're using a variable for something you shouldn't be. The issue isn't with constness, it's an issue of when the size of the array is needed.

You may be misunderstanding what const means. It only means that after the variable is initialized, it is never changed. For example this is legal:

void func(int x){
    const int i = x*5; //can't be known at compile-time, but still const
    //int array[i]; //<-- this would be illegal even though i is const 
}

int main(){
    int i;
    std::cin >> i;
    func(i);
    return 0;
}

To get around this limitation, in C++11 you can mark it as constexpr to indicate that the value can be determined at compile time. This seems to be what you want.

struct S
{
    int const i;
};
int main(){
    constexpr S const s = { 42 };
    char arr[s.i];
    return 0;
}

compile with:

$ c++ -std=c++11 -pedantic file.cpp


in C99, what you're doing is legal, the size of an array does not need to be known at compile time.

struct S
{
    int const i;
};
int main(){
    struct S const s = { 42 };
    char arr[s.i];
    return 0;
}

compile with:

$ cc -std=c99 -pedantic file.c

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
2

At least most of the time, const really means something much closer to "read-only" than to "constant". In C89/90, essentially all it means is "read-only". C++ adds some circumstances in which it can be constant, but it still doesn't even close to all the time (and, unfortunately, keeping track of exactly what it means when is non-trivial).

Fortunately, the "workaround" is to write your code the way you almost certainly should in any case:

std::vector<char> arr(s.i);

Bottom line: most use of a built-in array in C++ should be considered suspect. The fact that you can initialize a vector from a non-constant expression is only one of many advantages.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111