0

I have a small problem relating to namespaces, considering the following in a header file:

namespace A {
    namespace B {
        void SetMemberValue(double value) { _member = value; }
        double FunctionThatUsesMember(double a) { return a * _member; }
        double AnotherFuncThatUsesMember(double a) { return a / _member; }
        static double _member = 0.01;
    }
}

I did not want the user to be able to change the value of _member via A::B::_member = some_value. After reading up on unnamed namespaces I changed it to:

namespace A {
    namespace B {
        void SetMemberValue(double value) { _member = value; }
        double FunctionThatUsesMember(double a) { return a * _member; }
        double AnotherFuncThatUsesMember(double a) { return a / _member; }
        namespace {
            double _member = 0.01;
        }
    }
}

This forces the user to use the supplied mutator function and works great except for one problem:

If the user continues to use: A::B::_member = some_value the code does not fail to compile, link, or run; the statement is simply ignored and the default value of 0.01 is used possibly leading to run-time errors or "OMG WTF IS WRONG BBQ!!1!!" moments. (The statement not failing may be an issue with MSVC++ and VS2010 though I am not sure.)

Question: Is there a way to have the code fail LOUDLY in some way when A::B::_member = some_value is erroneously used?

Casey
  • 10,297
  • 11
  • 59
  • 88
  • If you put an anonymous namespace in the header file, each translation unit will have a `_member` in a different namespace! i.e. `A::B::::_member`, `A::B::::_member`. – Jesse Good Aug 29 '13 at 21:51
  • You don't want to do that... really... `static` variables (or unnamed namespaces) will create multiple `_member` variables, one per translation unit – David Rodríguez - dribeas Aug 29 '13 at 23:04

1 Answers1

2

First off, note that you get a different version of _member in each translation unit! I'm not sure if that is intentional or not.

If you actually want one _member in your program and you don't want the user to access a specific global variable, you shouldn't make it visible in the header! Put it into the source and provide functions to access it there:

// some-module.h
double getValue();
void   setValue(double value);

// some-module.cpp
#include "some-module.h"
static double value(0.01);
double getValue() { return value; }
void   setValue(double value) { ::value = value; }

I left out namespaces because they actually don't matter. You can use an unnamed namespace instead of static inside the translation unit but it doesn't make much of a difference, really.

If you claim that the extra function call is unacceptable and everything has to be in the header, you could make value a private member of a class. You'd still need to wrap it into a function to avoid duplicated symbols. If you also wrap the class into an unnamed namespace, you can have one version of the value per translation unit, too:

#if ONE_VALUE_PER_TRANSLATION_UNIT
namespace {
#endif

class Value
{
    static double& value() { static double rc(0.01); return rc; }
    friend double getValue();
    friend void   setValue(double value);
};
double getValue() { return Value::value(); }
void   setValue(double value) { Value::value() = value; }

#if ONE_VALUE_PER_TRANSLATION_UNIT
}
#endif

Obviously, you can add more function accessing the value in all of these case. I just demonstrated access using simple non-member function getValue() and setValue(). What you really expose is up to you.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Having duplicate values in each TU was unintentional. Moving the namespace definition to the `.cpp` file worked and fails to compile loudly with not one but TWO errors: `_member: _is not a member of A::B` (which it isn't! :D) and `_member: undeclared identifier` – Casey Aug 29 '13 at 22:00