Jul*_*n__ 5 c++ inheritance templates metaprogramming composition
我想使用组合并使用C++功能为每个可能的重载(noexcept,const,volatile)编写好的转发方法.
我们的想法是使用traits来确定方法是否被声明{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;
}
};
Run Code Online (Sandbox Code Playgroud)
这是我到目前为止**:
// 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)...);
}
Run Code Online (Sandbox Code Playgroud)
请注意,这个问题与下面的问题不同,因为我知道我们可以使用c ++特性来检查对象接口:组合:使用特征来避免转发函数?
**受到@David Stone的评论主题的启发:我什么时候应该使用C++私有继承?.
我们先从解决方案开始,一点一点地解释。
#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, &&)
Run Code Online (Sandbox Code Playgroud)
Inner 表示您要转发到的对象的类型,inner 表示其名称。限定符是成员函数中所需的 const、易失性、& 和 && 的组合。
noexcept 规范非常复杂,因为您需要处理函数调用以及构造返回值。如果您转发的函数返回一个引用,则您知道它是安全的(引用始终可以从同一类型构造 noexcept ),但如果该函数按值返回,则需要确保该对象的移动构造函数是 noexcept 。
我们可以通过使用默认模板参数 return_type 来稍微简化这一点,否则我们将不得不将该返回类型拼写两次。
我们在函数体中使用 static_cast 来正确添加 cv 和引用限定符到所包含的类型。函数上的引用限定符不会自动获取此值。
使用继承而不是组合
使用私有继承,解决方案看起来更像是这样:
struct Outer : private Inner {
using Inner::f;
};
Run Code Online (Sandbox Code Playgroud)
这样做的好处是
归档时间: |
|
查看次数: |
992 次 |
最近记录: |