Unique parameter values for interfaces

I'm currently trying to fortify my class api by "make interfaces easy to use correctly and hard to use incorrectly". I have a class as follows. class api { api(ConfigName const& configName_, PathName const& pathName_) : m_ConfigName(configName_.value) , m_PathName(pathName_.value) {} std::string m_ConfigName; std::string m_PathName; }; Both ConfigName and PathName are typedef to a template structure as follows. template<typename S> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value }; typedef ParameterValue<std::string> ConfigName; typedef ParameterValue<std::string> PathName; I realized later that this method doesn't prevent the swapping of a ConfigName with a PathName parameter. Since both parameters are typedef to the same "type" of ParameterValue they're interchangeable. Is there a boost class, library or C++ idiom that would provide what I'm looking for? Since I'm going to be using this concept for other classes I build, I'd like something that would easily create parameter classes to use but not be interchangeable with other classes of the same type. I know that I could do this with a macro but I'm leaving that for a last resort. Ryan

On Wed, May 6, 2009 at 2:12 PM, Ryan McConnehey <mccorywork@gmail.com> wrote:
I realized later that this method doesn't prevent the swapping of a ConfigName with a PathName parameter. Since both parameters are typedef to the same "type" of ParameterValue they're interchangeable. Is there a boost class, library or C++ idiom that would provide what I'm looking for? Since I'm going to be using this concept for other classes I build, I'd like something that would easily create parameter classes to use but not be interchangeable with other classes of the same type. I know that I could do this with a macro but I'm leaving that for a last resort.
One way to do this is to simply define new types instead of using typedef to create different aliases for the same type. As for Boost, I guess that Boost.Parameter could help you allow your users to avoid the mistake of mixing up the arguments by way of named arguments. Regards, Eugene Wee

Eugene Wee wrote:
One way to do this is to simply define new types instead of using typedef to create different aliases for the same type.
Do you mean like this? struct ConfigName { ConfigName(std::string const& value_) : value(value_) {} std::string value; }; struct PathName { PathName(std::string const& value_) : value(value_) {} std::string value; }; If so, I'm trying to cut down on code duplication and have a standard way of accessing my parameter values. By created each parameter value separately there is nothing that forces the programmer to have consistent interface to access the value. Ryan

2009/5/6 Ryan McConnehey <mccorywork@gmail.com>
I'm currently trying to fortify my class api by "make interfaces easy to use correctly and hard to use incorrectly". I have a class as follows.
class api { api(ConfigName const& configName_, PathName const& pathName_) : m_ConfigName(configName_.value) , m_PathName(pathName_.value) {}
std::string m_ConfigName; std::string m_PathName; };
Both ConfigName and PathName are typedef to a template structure as follows.
template<typename S> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value };
typedef ParameterValue<std::string> ConfigName; typedef ParameterValue<std::string> PathName;
I realized later that this method doesn't prevent the swapping of a ConfigName with a PathName parameter. Since both parameters are typedef to the same "type" of ParameterValue they're interchangeable. Is there a boost class, library or C++ idiom that would provide what I'm looking for? Since I'm going to be using this concept for other classes I build, I'd like something that would easily create parameter classes to use but not be interchangeable with other classes of the same type. I know that I could do this with a macro but I'm leaving that for a last resort.
Ryan
Try this: template<typename S, *int N*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value }; typedef ParameterValue<std::string, *0*> ConfigName; typedef ParameterValue<std::string, *1*> PathName; Roman Perepelitsa.

Roman Perepelitsa wrote:
template<typename S, *int N*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value };
typedef ParameterValue<std::string, *0*> ConfigName; typedef ParameterValue<std::string, *1*> PathName;
Roman Perepelitsa.
Is is possible to have the number be generated automatically so that it doesn't need to be defined by the user? Ryan

2009/5/6 Ryan McConnehey <mccorywork@gmail.com>
Roman Perepelitsa wrote:
template<typename S, *int N*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value };
typedef ParameterValue<std::string, *0*> ConfigName; typedef ParameterValue<std::string, *1*> PathName;
Roman Perepelitsa.
Is is possible to have the number be generated automatically so that it doesn't need to be defined by the user?
I don't think so. If you want to protect yourself from accidentally using the same number with different types, you can try the following: template<typename S, *typename Tag*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value }; *struct ConfigNameTag {};* typedef ParameterValue<std::string, *ConfigNameTag*> ConfigName; *struct PathNameTag {};* typedef ParameterValue<std::string, *PathNameTag*> PathName; Roman Perepelitsa.

Quoting Roman Perepelitsa <roman.perepelitsa@gmail.com>:
2009/5/6 Ryan McConnehey <mccorywork@gmail.com>
Roman Perepelitsa wrote:
template<typename S, *int N*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value };
typedef ParameterValue<std::string, *0*> ConfigName; typedef ParameterValue<std::string, *1*> PathName;
Roman Perepelitsa.
Is is possible to have the number be generated automatically so that it doesn't need to be defined by the user?
I don't think so. If you want to protect yourself from accidentally using the same number with different types, you can try the following: [...]
In addition to tagging, you can also look into whether true_typedef is suitable. Matthew Wilson's STLSoft has an implementation. There is also a strong_typedef in Boost but I think it should be regarded as implementation detail of the serialization library and thus comes with caveats.

Peter Bartlett wrote:
In addition to tagging, you can also look into whether true_typedef is suitable. Matthew Wilson's STLSoft has an implementation.
true_typedef seems like a really good choice. I'm unclear what the STLSOFT_GEN_OPAQUE macro really provides. The macro is defined as follows. #define STLSOFT_GEN_OPAQUE (type) typedef struct __stlsoft_htype##type{ int i; } const* type; So to use the STLSoft version I have to use the macro and then provide the typedef. It would look like this. STLSOFT_GEN_OPAQUE (ConfigName_u) typedef stlsoft::true_typedef<std::string, ConfigName_u> ConfigName; How is this better than just declaring a struct in the typedef itself. It would look like this. typedef stlsoft::true_typedef<std::string, struct ConfigName_u> ConfigName; What does having a pointer to a struct provide that a normal struct doesn't? Ryan

Peter Bartlett wrote:
In addition to tagging, you can also look into whether true_typedef is suitable. Matthew Wilson's STLSoft has an implementation.
true_typedef seems like a really good choice. I'm unclear what the STLSOFT_GEN_OPAQUE macro really provides. The macro is defined as follows. #define STLSOFT_GEN_OPAQUE (type) typedef struct __stlsoft_htype##type{ int i; } const* type; So to use the STLSoft version I have to use the macro and then provide the typedef. It would look like this. STLSOFT_GEN_OPAQUE (ConfigName_u) typedef stlsoft::true_typedef<std::string, ConfigName_u> ConfigName; How is this better than just declaring a struct in the typedef itself. It would look like this. typedef stlsoft::true_typedef<std::string, struct ConfigName_u> ConfigName; What does having a pointer to a struct provide that a normal struct doesn't? Ryan

template<typename S, *int N*> struct ParameterValue { ParameterValue(S value_) : value(value_) {} S value };
typedef ParameterValue<std::string, *0*> ConfigName; typedef ParameterValue<std::string, *1*> PathName;
You could use inheritance the use of numeric tagging. template <typename T> struct Param { T value; }; struct ConfigName : Param<string> { }; struct PathName : Param<string> { }; Andrew Sutton andrew.n.sutton@gmail.com
participants (5)
-
Andrew Sutton
-
Eugene Wee
-
Peter Bartlett
-
Roman Perepelitsa
-
Ryan McConnehey