11

The inline keyword in C++ allows functions to be defined in headers so that the compiler can either actually inline them or leave only one copy of the function. This allows reducing the number of compilation units by defining the functions directly in headers, with the advantage of often several times faster compilation time and possibly faster execution.

Why can't this same pattern be applied to namespace-scope variables, while functions in C++ actually are namespace-scope variables when viewing them as a special pointer?

What I can think of is using a static local variable of an inline function.

inline std::string& Hello__() { //Edit: Added the &
    static std::string hello("Hello");
    return hello;
}

#define Hello (Hello__())

Edit: I'd like to clarify my question as below.

I'm using the term 'inline' as what the compiler understands. It lets the same definition with the same name be in multiple compilations units, allowing the definition in the header. The main advantage of 'inline' is not the performance benefit as a macro function would have but the shorter compilation time from the reduced number of compilation units. It can possibly be several times shorter.

I did come out with a solution to let a variable work like an inline function. But I am still finding for a better way to do this.

To state again clearly, what I want to achieve is defining a namespace-scope variable in the header like an inline function, in order to make the build process as simple and fast as possible.


Edit2: Thank you for the link in the comment by dyp. I've just read the proposal, and that is exactly what I am thinking of. What is the current status of that proposal?

Quoted from the proposal:

However, it is not uncommon to desire the existence of a globally­ unique object without having to pick a single translation unit in which to define it. As a practical matter, making this choice generally requires either the use of non­trivial preprocessor macros, separately compiled libraries, or both. However, one strength of C++ is its ability to support the development of header­only libraries. In this vein, the lack of the ability to define an inline variable poses a significant constraint on library design.

  • how would inlining the function be different from "inlining the variable" as you say? – Ryan Haining May 25 '15 at 23:29
  • 4
    I see your proposed solution, but what is the problem you're trying to solve? – MSalters May 25 '15 at 23:34
  • @MSalters I want to know if there is a better way to achieve this, or whether there was a specific reason not to allow inline variables. –  May 25 '15 at 23:35
  • 1
    @xiver77: Functions can be inlined because they are immutable. In your example, `hello` is mutable, and so its value must be shared between the places that use it (so that changes in one place are visible to the other places). – Mankarse May 25 '15 at 23:36
  • @Mankarse the `inline` keyword does not only imply that. Its more general meaning is allowing the definition in the header. –  May 25 '15 at 23:38
  • 1
    The purpose of inlining a function is the absence of function call and enabling other optimizations. What you've said is at best a minor side-effect, not necessarily a good one, and most of the time plain wrong. – Elazar May 25 '15 at 23:38
  • @xiver77: to achieve what? what is the problem you're trying to solve? – Karoly Horvath May 25 '15 at 23:39
  • 10
    This proposal might be related to your question: http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4424.pdf – dyp May 25 '15 at 23:41
  • @Mankarse this is not exactly immutability, but the compile-time knowledge. – Elazar May 25 '15 at 23:44
  • 1
    @Elazar What you've said is not the point of this question, and I don't understand what you mean by 'not necessarily good' or 'plain wrong'. –  May 25 '15 at 23:57
  • 1
    Reducing the number of compilation units is not the main purpose of the keyword. The purpose is to give you a tool that will help you write the code in a way that will help inlining without whole-program analysis or something. If inlining was not a possibility, there was no `inline` keyword (or equivalent). Macros are definitely not a replacement. – Elazar May 26 '15 at 00:02
  • 1
    I believe the OP's description of `inline` is correct. The keyword `inline` doesn't have anything to do with what we usually refer to when we talk about inlining. See http://stackoverflow.com/questions/1759300/when-should-i-write-the-keyword-inline-for-a-function-method So the question does make sense to me. – Theodoros Chatzigiannakis May 26 '15 at 00:10
  • 3
    In all honesty, the yellow quote square has a very good point I would love to see solved too. this would help a lot cohesion when declaring classes with static variables. not having to chose one .cpp just to help poor little linker. inline here means `coalesce definition`. – v.oddou May 26 '15 at 00:24
  • 2
    I'm all for this. I recently tried to use some header-only part of wxWidgets, but it failed to link because `wxString::npos` was referred to. Linking in the library that held that definition increased my executable size by 25MB; I ended up putting my own definition of it in instead! It'd be great if `npos` did not require linking of a spsecific definition. – M.M May 26 '15 at 00:42
  • 1
    @Mankarse: I think mutability is the real issue. C++ is designed not to require a particularly sophisticated linker, and does not require that definitions of an `inline` function within two different compilation units can't result in an executable which contains two copies of that function. Having variables work as desired would be nice, but some linkers would have trouble guaranteeing that all but one definition *and allocation* would get ignored. – supercat May 26 '15 at 23:22
  • Related [Why the static data members have to be defined outside the class separately in C++ (unlike Java)?](http://programmers.stackexchange.com/q/145299/24410). Here I discuss the similar problem just that the context is for class's static members, but it can equally be applied to global data too. – iammilind Sep 18 '15 at 11:17
  • Mutability is definitely an issue here. If I take you temporary solution of using static variable inside an inline function and that function is now compiled and linked into several compilation units, what would a function inside compilation unit X see when I change the return value inside another function inside compilation unit Y. I suggest you try it and let me know if that is you desired behaviour. – Uri Brecher Apr 25 '16 at 05:03
  • 1
    This feels like the problem that [`__declspec(selectany)`](https://msdn.microsoft.com/en-us/library/5tkz6s71.aspx) was created for. MSVC only, though. Don't know if there's a non-MS equivalent. – Ryan Bemrose Apr 25 '16 at 07:03

4 Answers4

16

C++17 has inline variables, see: N4424.

gnzlbg
  • 7,135
  • 5
  • 53
  • 106
  • Worth noting that g++ 6.4.0, Ubuntu 16.04, has the flag `-std=c++17`, but still fails with the error, likely not implemented yet at that point. The same code works on newer GCC however: https://stackoverflow.com/questions/38043442/how-do-inline-variables-work/53896763#53896763 – Ciro Santilli OurBigBook.com Feb 08 '19 at 13:58
2

Here is a short experiment I did with your suggestion:

file a.cpp:

inline int& get_inline_int() {
    static int my_inline_int = 0;
    return my_inline_int;
}

void set_me(int x) {
    get_inline_int() = x;
}

file b.cpp:

#include <iostream>

inline int& get_inline_int() {
    static int my_inline_int = 0;
    return my_inline_int += 2;
}

void show_me() {
    std::cout << get_inline_int() << std::endl;
}

file main.cpp:

void set_me(int);
void show_me();

int main() {
    set_me(7);
    show_me();
    set_me(8);
    show_me();
    return 0;
}

I cheated a little and gave two different implementations to the same function. Without inline the linker will complain about duplicate symbol, but I get away with it with the inline in use.

I have to admit that the result surprised me. I tried it with both g++ and clang++ and got similar results:

clang++ a.cpp b.cpp main.cpp -o runme

will output

7
8

clang++ b.cpp a.cpp main.cpp -o runme

will output

9
10

So, I consider this a misuse of the language because the compilation result is unpredictable and usually not what you meant it to be. If a committee will be able to define a behaviour that is predictable I would use these so called "inline" variables myself.

Uri Brecher
  • 437
  • 2
  • 11
  • Why do you find the result unpredictable if you can reproduce it on two different compilers? – Chiel Apr 26 '16 at 11:39
  • 1
    Maybe that is not the right way to describe this behaviour. However I wouldn't use any feature that depends on linkage order. – Uri Brecher Apr 26 '16 at 11:50
0

Variables actually can be inlined, but they would not be globally the same then.

zzz.h:

#ifndef ZZZ_H_b6e267bb76401a0cd6502e426a702e41d792a853
#define ZZZ_H_b6e267bb76401a0cd6502e426a702e41d792a853

namespace {
    int omg;
}

static int hello;

// int thisWouldBreakCompilationSoIsCommentedOut;

#endif

xxx.cpp:

#include "zzz.h"

zzz.cpp:

#include "zzz.h"

int main() {}

Let's see if it compiles altogether:

$ g++ xxx.cpp zzz.cpp
$
bipll
  • 11,747
  • 1
  • 18
  • 32
-1

Your "inlined variable" Hello behaves exactly like a global variable would. The only difference is that, in addition to its declaration in a header, a global variable also requires a definition in a single compilation unit while Hello does not need that.

I guess, the reason why there is no language support for "inlined variables" is simply that global variables are rightly considered evil anyway. You simply don't use them in modern code. As such, languages should not add complexity to their syntax to support something that's not used anyway.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106