函数参数分组和constness
Function arguments grouping and constness
我们正在尝试重构我们的代码,我们想要的改进之一是:许多函数有许多参数,但其中许多函数共享一个公共子集。所以,我们想要创建一个结构来对它们进行分组。问题是,有些函数需要一些形参为const,有些则不需要。其中一些函数必须能够调用提供此参数分组结构的这些函数的子集,但在以下限制下:被调用的函数不能"降低"此结构的稳定性(参见以下示例)。实现该结构的所有必要变体解决了问题,但并不优雅。我们正在研究的一个解决方案是使用模板,例如:
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
foo1(my_cont);
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont);
}
我们的问题是,foo2调用foo1时,编译器不会报错,而我们希望正好相反。这有可能用模板实现吗?还有其他的技巧吗?
两者都不行。模板的不同实例是不相关的类型,它们之间没有隐式转换。所以my_container<int, char, float const>
, my_container<int const, char,
float const>
和my_container<int, char, float>
都是不相关的类型,它们之间没有隐式转换。
应该可以使用继承、使用元编程技巧来确定继承的对象,但我不是当然可以,而且我怀疑这样做会得不偿失。
在不与未定义行为接壤的情况下,这可以通过另一层间接实现。添加一个引用原始成员的视图类。Constness可以隐式添加,但不能删除。
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
template <class A, class B, class C>
class my_container_view
{
A* a_;
B* b_;
C* c_;
public:
template <class A_, class B_, class C_>
my_container_view(my_container<A_, B_, C_>& source):
a_(&source.a), b_(&source.b), c_(&source.c)
{}
template <class A_, class B_, class C_>
my_container_view(my_container_view<A_, B_, C_>& source):
a_(&source.a()), b_(&source.b()), c_(&source.c())
{}
A& a() const { return *a_; }
B& b() const { return *b_; }
C& c() const { return *c_; }
};
void foo1(my_container_view<int, char, float const> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
}
void foo2(my_container_view<int const, char, float const> my_cont)
{
my_cont.a() /*= 10*/;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
//foo1(my_cont); //not allowed
}
void foo3(my_container_view<int, char, float> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() = 3.14;
t
foo2(my_cont);
}
int main()
{
my_container<int, char, float> mc;
foo1(mc);
foo2(mc);
foo3(mc);
}
我有我的怀疑,虽然,这到底值多少钱。通常对于类,要么你可以修改它的所有成员——你只是不修改那些你不想修改的成员——要么你不能修改任何成员。如果您想要这种级别的控制,您宁愿单独传递每个参数—与您所做的相反。
我的解决方案是一点元编程。看起来很丑,没有经过全面测试,但无论如何:这样,一切都应该正常运行
#include <iostream>
#include <boost/type_traits.hpp>
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
template<typename An, typename Bn, typename Cn>
operator my_container<An,Bn,Cn>& ()
{
/* First, check whether compatible at all */
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<A>::type, typename boost::remove_cv<An>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<B>::type, typename boost::remove_cv<Bn>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<C>::type, typename boost::remove_cv<Cn>::type>::value));
/* Enforce const'ness */
BOOST_STATIC_ASSERT( !boost::is_const<A>::value || boost::is_const<An>::value );
BOOST_STATIC_ASSERT( !boost::is_const<B>::value || boost::is_const<Bn>::value );
BOOST_STATIC_ASSERT( !boost::is_const<C>::value || boost::is_const<Cn>::value );
return *reinterpret_cast< my_container<An,Bn,Cn>* >(this);
}
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
//foo1(my_cont); /// BOOST_STATIC_ASSERT fails! Hurray!
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont); /// No complaints! Hurray!
}
int main(int argc, char* argv[])
{
my_container<int,char,float> foobar;
foo3(foobar);
return 0;
}
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- reduce函数的第二个rhs参数中tbb::parallel_reduce:constness的Lambda形式
- 将函数参数的"constness"复制到其返回类型 C++
- 将参数作为引用传递给具有(no) constness的指针会给出不同的地址
- 函数参数分组和constness