我想使用组合并使用C ++功能为每个可能的重载(noexcept,const,volatile)编写好的转发方法。
我们的想法是使用特征来确定方法是否被声明{noexcept / const / volatile / etc.}并且相应地表现。
以下是我想要实现的一个例子:
struct User{
UsedObject& obj;
User(UsedObject& obj) : obj(obj) {}
FORWARD_METHOD(obj, get); //here is where the forwarding happens
};
struct UsedObject{
string m{"Hello\n"};
string& get(double d){
cout << "\tUsed :const not called...\n";
return m;
}
const string& get(double d) const{
cout << "\tUsed :const called...\n";
return m;
}
};
这是我到目前为止所拥有的**:
// forward with noexcept attribute
// I'm not 100% sure about : std::declval<std::add_lvalue_reference<decltype(obj)>::type
template<typename... Args>
constexpr decltype(auto) get(Args && ... args)
noexcept(
noexcept(std::declval<std::add_lvalue_reference<decltype(obj)>::type>().get( std::forward<Args>(args)... ))
and
std::is_nothrow_move_constructible<decltype( std::declval<std::add_lvalue_reference<decltype(obj)>::type>().get( std::forward<Args>(args)... ) )>::value
)
{
cout << "const called...\n";
return obj.get(std::forward<Args>(args)...);
}
// forward with noexcept and const attributes
// I'm not sure that this one behave properly.
template<typename... Args>
constexpr decltype(auto) get(Args && ... args)
const noexcept(
noexcept(std::declval< std::add_const<decltype(obj) &>::type >().get( std::forward<Args>(args)... ))
and
std::is_nothrow_move_constructible<decltype( std::declval< std::add_const<decltype(obj) &>::type >().get( std::forward<Args>(args)... ) )>::value
)
{
cout << "const not called...\n";
using const_type = std::add_lvalue_reference<std::add_const<std::remove_reference<decltype(obj)>::type>::type>::type;
return const_cast<const_type>(obj).get(std::forward<Args>(args)...);
}
请注意,这个问题与下面的问题不同,因为我知道我们可以使用c ++特征来检查对象接口:Composition: using traits to avoid forwarding functions?
**灵感来自@David Stone的评论主题:When should I use C++ private inheritance?。
答案 0 :(得分:1)
让我们从解决方案开始,逐一解释。
#define FORWARDING_MEMBER_FUNCTION(Inner, inner, function, qualifiers) \
template< \
typename... Args, \
typename return_type = decltype(std::declval<Inner qualifiers>().function(std::declval<Args &&>()...)) \
> \
constexpr decltype(auto) function(Args && ... args) qualifiers noexcept( \
noexcept(std::declval<Inner qualifiers>().function(std::forward<Args>(args)...)) and \
( \
std::is_reference<return_type>::value or \
std::is_nothrow_move_constructible<return_type>::value \
) \
) { \
return static_cast<Inner qualifiers>(inner).function(std::forward<Args>(args)...); \
}
#define FORWARDING_MEMBER_FUNCTIONS_CV(Inner, inner, function, reference) \
FORWARDING_MEMBER_FUNCTION(Inner, inner, function, reference) \
FORWARDING_MEMBER_FUNCTION(Inner, inner, function, const reference) \
FORWARDING_MEMBER_FUNCTION(Inner, inner, function, volatile reference) \
FORWARDING_MEMBER_FUNCTION(Inner, inner, function, const volatile reference)
#define FORWARDING_MEMBER_FUNCTIONS(Inner, inner, function) \
FORWARDING_MEMBER_FUNCTIONS_CV(Inner, inner, function, &) \
FORWARDING_MEMBER_FUNCTIONS_CV(Inner, inner, function, &&)
Inner表示要转发的对象的类型,inner表示其名称。限定符是const,volatile,&amp;和&amp;&amp; amp;的组合。您需要的成员函数。
noexcept规范非常复杂,因为你需要处理函数调用以及构造返回值。如果你要转发的函数返回一个引用,你知道它是安全的(引用总是不可以从同一类型构造),但如果函数返回值,你需要确保对象的移动构造函数是noexcept
我们能够通过使用默认模板参数return_type来简化这一点,否则我们将不得不拼写两次返回类型。
我们在函数体中使用static_cast来处理正确添加cv和引用限定符到包含的类型。这个函数不会通过参考限定符自动获取。
使用继承代替合成
使用私有继承,解决方案看起来更像是这样:
struct Outer : private Inner {
using Inner::f;
};
这具有
的优点