问题
I am currently writing an interface class that should provide access to to internal elements of a complex structure as const or non-const references. The idea is that some modules are granted const access and some modules are granted full access.
I have used the 'type_traits' 'std::add_const' to conditionally qualify the return type of the internal member functions, unfortunately I cannot think of a way of conditionally qualifiying the member functions as const or non-const.
Is this even possible? if so how?
E.G:
template< typename T, bool isConst >
struct apply_const
{
typedef T type;
};
template<typename T>
struct apply_const<T, true>
{
typedef typename std::add_const<T>::type type;
};
template< bool isConst >
const Interface
{
/// @brief get the TypeA member
typename apply_const<TypeA, isConst >::type& GetXpo3Container() // how do I conditionally add a const qualifier
{
return config_.type_a_member_;
}
typename apply_const<Profile, isConst >::type& GetProfile( unint32_t id ) // qualifier ???
{
return config_.profiles.get( id );
}
// .... lots more access functions
ConfigType config_; // the config
};
Note: the underlying reason for separating / creating 2 versions of the interface is that they will be providing access to different instances of config
- one which is writable and one which is not. The sub-system being developed is an embedded Netconf Agent, which supports <running>
and <candidate>
configurations.
回答1:
This seems easiest to do with a specialization:
template< bool isConst >
struct Interface;
template <>
struct Interface<false>
{
TypeA& GetXpo3Container()
{
return config_.type_a_member_;
}
};
template <>
struct Interface<true>
{
const TypeA& GetXpo3Container() const
{
return config_.type_a_member_;
}
};
Edit: although I'm not entirely sure what this adds. Wouldn't it be easier to have
struct Interface
{
TypeA::type& GetXpo3Container()
{
return config_.type_a_member_;
}
const TypeA::type& GetXpo3Container() const
{
return config_.type_a_member_;
}
};
and use const Interface
where appropriate? Or is this not an option for some other reason?
Edit 2: my std::enable_if
use was wrong, it's gone now.
回答2:
You can use SFINAE:
template<bool isConst>
struct Interface
{
template<
bool Cond = isConst
, typename std::enable_if<!Cond, int>::type = 0
>
TypeA&
GetXpo3Container() const
{
return config_.type_a_member_;
}
template<
bool Cond = isConst
, typename std::enable_if<Cond, int>::type = 0
>
TypeA const&
GetXpo3Container() const
{
return config_.type_a_member_;
}
};
Note that the two members need to be made templates and that I'm using a default parameter to force typename std::enable_if<Cond, int>::type
to be dependent -- in the scope of the class std::enable_if<isConst, int>::type
is not dependent and thus will net a hard-error when the class is instantiated whereas we want SFINAE.
However the default parameter means that someone can do e.g. Interface<true> f; TypeA& ref = f.GetXpo3Container<false>();
. If you want to avoid that (e.g. you don't trust users to not misuse unspecified bits of your interface) here's another way to make the member type
of std::enable_if
dependent again which is perhaps more appropriate, but somewhat more arcane:
template<typename T, T Value, typename>
struct depend_on_c {
static constexpr T value = Value;
};
/* and in the scope of Interface: */
template<
typename Dummy = void
, typename std::enable_if<
depend_on_c<bool, isConst, Dummy>::value
, int
>::type = 0
>
/* rest as before */
回答3:
You can specialize your template for the case that isConst
is true, and make all the member functions const
in this case, whilst leaving them non-const
in the primary template.
Alternatively, write two versions of the member functions (one const
and one not), and use enable_if
to only have the appropriate overload enabled.
来源:https://stackoverflow.com/questions/10110082/adding-a-const-qualifier-to-a-member-function