3

First, I have read this very informative answer about stylistic difference between defining a constexpr variable vs constexpr function. My question is more related with the final size of the binary when using these two. Consider this code:

// approach 1
template <typename T>
struct foo
{
  static constexpr char name[] = "mickey";
};

// approach 2
template <typename T>
struct bar
{
  static constexpr const char* getName() { return "mickey"; }
};

const char* func1() { return foo<int>::name; }
const char* func2() { return foo<double>::name; }

const char* func3() { return bar<int>::getName(); }
const char* func4() { return bar<double>::getName(); }

Look at this code in this godbolt link as well. While approach 1 returns different copies of name, approach 2 returns only one copy for all the different instantiations for different T. Infact, when I created 100 different types approach 2 led to a considerably smaller binary. Was wondering if anyone has experienced something similar.

Community
  • 1
  • 1
skgbanga
  • 2,477
  • 2
  • 20
  • 29

1 Answers1

4

Well, those two approaches aren't really the same. There are things you can do with foo<T>::name that you cannot do with bar<T>::getName(): I can take a pointer to it and I can take a reference to it. That ability prevents different foo<T>::names from being the same.

But with getName(), there's no such issue. You just get a prvalue - you can't take its address. The different bar<T>::getName functions themselves have to be different, but not the underlying storage.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • While true, doesn't really help if your goal is to minimize the size of the executable, to which the existence of this question attests. Not your fault — it's entirely unclear as to what the question _is_. – Lightness Races in Orbit Aug 04 '16 at 23:17
  • @LightnessRacesinOrbit I interpreted the question as "why is there a difference?" – Barry Aug 04 '16 at 23:30
  • @LightnessRacesinOrbit: Apologies for being unclear in the question. Barry's reply is exactly what I was seeking for. (I reached there via a convoluted way though) – skgbanga Aug 05 '16 at 01:34
  • You can't odr use `foo::name` being it a `constexpr`. Am I wrong? You can't _take a pointer or a reference to it_ indeed. – skypjack Aug 05 '16 at 06:30
  • `struct S { static constexpr int v = 42; }; int main() { const int *p = &S::v; }` results with an undefined reference to `S::v` when the linker takes its part to the game. Because you *can't* take the address of a `constexpr` variable. Of course, unless you add `constexpr int S::v;` somewhere, but to odr use a `constexpr` doesn't make much sense indeed. – skypjack Aug 05 '16 at 12:13
  • @skypjack That has nothing to do with constexpr. You just didn't add a definition. – Barry Aug 05 '16 at 12:15
  • @Barry You need a definition, because you can't odr-use a constexpr variable otherwise. That is the point of the first comment. We are in a loop. :-D – skypjack Aug 05 '16 at 12:37
  • @skypjack Again, that has nothing to do with constexpr. You can't odr-use anything without a definition. Constexpr variables can have definitions. – Barry Aug 05 '16 at 12:41
  • @Barry Well, right, but we are speaking about constexpr variables!! What I'm saying is that you can _use_ them, but you cannot odr-use them without a definition (and we agree on that, let's use the right terms) that is quite uncommon for a constexpr. On the other side, from the answer it seems that you can take the address of a constexpr as mentioned in the OP's example, that is not possible (they have not a definition). So, at least, it's worth to mention it, otherwise the reader (a not so expert one) could misunderstand. That's all. – skypjack Aug 05 '16 at 12:48