У меня есть небольшая проблема, связанная с пространствами имен, учитывая следующее в заголовочном файле:
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;
}
}
Я не хотел, чтобы пользователь мог изменять значение _member
с помощью A::B::_member = some_value
, После прочтения безымянных пространств имен я изменил его на:
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;
}
}
}
Это заставляет пользователя использовать предоставленную функцию мутатора и прекрасно работает, за исключением одной проблемы:
Если пользователь продолжает использовать: A::B::_member = some_value
код делает не не может скомпилировать, связать или запустить; утверждение просто игнорируется и значение по умолчанию 0.01
может привести к ошибкам во время выполнения или «OMG WTF IS WRONG BBQ !! 1 !!» моменты. (Утверждение, что это не так, может быть проблемой MSVC ++ и VS2010, хотя я не уверен.)
Вопрос: Есть ли способ сделать код неудачным в некотором роде, когда A::B::_member = some_value
ошибочно используется?
Прежде всего, обратите внимание, что вы получаете другую версию _member
в каждом переводчике! Я не уверен, является ли это намеренным или нет.
Если вы действительно хотите один _member
в вашей программе, и вы не хотите, чтобы пользователь обращался к определенной глобальной переменной, вы не должны делать это видимым в заголовке! Поместите его в источник и предоставьте функции для доступа к нему:
// 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; }
Я пропустил пространства имен, потому что они на самом деле не имеют значения. Вы можете использовать безымянное пространство имен вместо static
внутри блока перевода, но это не имеет большого значения, на самом деле.
Если вы утверждаете, что дополнительный вызов функции недопустим и все должно быть в заголовке, вы можете сделать значение закрытым членом класса. Вы все еще должны были бы обернуть его в функцию, чтобы избежать дублирования символов. Если вы также включите класс в безымянное пространство имен, вы также можете иметь одну версию значения на единицу перевода:
#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
Очевидно, что вы можете добавить больше функций для доступа к значению во всех этих случаях. Я только что продемонстрировал доступ с помощью простой функции, не являющейся членом getValue()
а также setValue()
, То, что вы действительно выставляете, зависит от вас.
Других решений пока нет …