我们正在尝试重构我们的代码,我们想要的改进之一是:许多函数有很多参数,但其中许多共享一个共同的子集。因此,我们希望创建一个将它们分组的结构。问题是有些函数需要一些参数是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,我们想要完全相反。这甚至可以用模板实现吗?还有其他技术吗?
答案 0 :(得分:1)
两者都不应该奏效。模板的不同实例化是
未删除的类型,它们之间没有隐式转换。所以
my_container<int, char, float const>
,my_container<int const, char,
float const>
和my_container<int, char, float>
都是无关的
类型,它们之间没有隐式转换。
应该可以使用继承来计算一些东西 元编程技巧来确定你继承的是什么,但我不是 确定如何,我怀疑这将是更多的努力而不是它的价值。
答案 1 :(得分:1)
不依赖于未定义的行为,这可以通过另一个间接层来实现。添加引用原始成员的视图类。可以隐式添加常量,但不能删除。
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);
}
(但我怀疑,这是多少值得。通常在课程中,你可以修改其所有成员 - 你只是不修改你不想要的那些 - 或者你可以'修改任何。如果你想要这个级别的控制,你宁愿单独传递每个参数 - 与你正在做的相反。)
答案 2 :(得分:0)
我的解决方案有点元编程。看起来很丑陋并没有经过全面测试,但无论如何: 这样,一切都应该“开箱即用”
#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;
}