我需要允许用户同时更改两个相同类型的数据结构的成员。例如:
struct Foo { int a, b; }
Foo a1 = {1,2}, a2 = {3,4};
dual(a1,a2)->a = 5;
// Now a1 = {5,2} and a2 = {5,2}
我有一个有效的类,它首先改变a1然后将a1复制到a2中。只要这样就可以了:
有没有办法获得这种行为:
dual(a1,a2)->a = 5;
// Now a1 = {5,2} and a2 = {5,4}
我接受了替代语法,但是它们应该保持简单,我想避免像:
set_members(a1, a2, &Foo::a, 5);
members(a1, a2, &Foo::a) = 5;
或任何涉及明确指定&Foo::
[编辑]
我应该更精确。关键是要使用图形库。该库在有向图上工作,但是使用规定给定两个顶点v1和v2,如果存在边v1-> v2,则将存在边v2-> v1。并且这两个边缘经常(但不总是)具有相同的属性。所以现在的实现现在允许:
G.edge(v1,v2)->b = 5; // Only v1->v2 is modified
G.arc(v1,v2)->a = 10;
// Now G.edge(v2,v1) is set to G.edge(v1,v2) after the modification a = 10 (i.e. b = 5 too)
我希望这个符号暗示只有a
被修改。
答案 0 :(得分:2)
使用Boost.Lambda的相对简单的解决方案:
#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;
template<typename T, typename U, typename V>
void dual(const T& functor, U& a1, V& a2)
{
functor(a1);
functor(a2);
}
struct Foo
{
int a;
};
struct Bar
{
char a;
};
int main()
{
Foo a1;
Bar a2;
dual(_1 = 5, a1.a, a2.a);
}
使用可变参数模板扩展dual()/ Boost.Preprocessor shenanigans留给读者练习。
答案 1 :(得分:2)
//获取所需的语法
template<class T>
class SetPropertyProxy
{
public:
SetPropertyProxy(T& _v1, T& _v2)
: a(_v1, _v2) {}
class A_Property_Proxy
{
public:
A_Property_Proxy(T& _v1, T& _v2): v1(_v1), v2(_v2) {}
A_Property_Proxy& operator = (T::A_Property_Type val)
{
v1.a = val;
v2.a = val;
return *this;
}
private:
T& v1;
T& v2;
}
//public member "a"
A_Property_Proxy a;
};
//helper function
template<class T>
SetPropertyProxy<T> dual(T& a , T& b)
{ return SetPropertyProxy<T>(a,b); }
//usage
dual(a,b).a = 5; //calls A_Property_Proxy::operator =
通过按属性类型进行参数化并引用属性而不是对属性容器的引用(在这种情况下为边缘),可以进一步改进A_Property_Proxy类的可重用性。
template<class U>
class Property_Proxy
{
public:
Property_Proxy(U& _v1prop, U& _v2prop): v1prop(_v1prop), v2prop(_v2prop) {}
Property_Proxy& operator = (U val)
{
v1prop = val;
v2prop = val;
return *this;
}
private:
U& v1prop;
U& v2prop;
}
答案 2 :(得分:0)
修改(将此放在此处,因为评论没有格式化)
所以你说你当前的代码有很多:
G.edge(v3,v4)->a = 2;
G.edge(v3,v4)->b = 2;
G.edge(v4,v5)->a = 6;
G.edge(v4,v5)->b = 6;
还有一点:
G.edge(v5,v6)->a = 4;
G.edge(v5,v6)->b = 7;
你的目标是[1]更容易发现那些特殊情况[2]更简洁的代码?
----- 原始答案,现在可能无关紧要-----
这是一个大致的想法,有很多可能的改进:
class MagicBag
{
private:
// you could make the whole class a template
// instead of hard-coding Foo..
vector<Foo *> m_vec;
public:
// store references to the items
void Add(Foo *f) { m_vec->push_back(f); }
// you can do overloads instead of these setters...
void set_a(int val) {
for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i)
(*i)->a = val;
}
void set_b(int val) {
for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i)
(*i)->b = val;
}
}
用法:
Foo a1 = {1,2}, a2 = {3,4};
MagicBag mb;
mb.Add(&a1);
mb.Add(&a2);
mb.set_a(5); // now a1.a = 5 and a2.a = 5
// etc.
在支持Properties的语言(如C#)中,这在语义上更容易。那里的最终语法是:
mb.a = 5;
答案 3 :(得分:0)
通过引入滥用模板,我可以获得大部分所需的语法。这编译和工作,但不保证它。它需要添加一些要使用的结构的宏,并且需要使用set_ *而不是直接赋值。
#include <iostream>
#define PROPERTY_MAP(ClassName) \
struct hidden_Mapper { \
ClassName * m_d1; \
ClassName * m_d2; \
hidden_Mapper(Data * d1, Data * d2) : \
m_d1(d1), m_d2(d2) {}
#define DECLARE_PROPERTY(name)\
template <typename ValueType> \
void set_##name(const ValueType & value) \
{ m_d1->name = value; m_d2->name = value; } \
#define END_PROPERTY_MAP };
template<typename ClassType>
typename ClassType::hidden_Mapper dual(ClassType & d1, ClassType & d2)
{
return typename ClassType::hidden_Mapper(&d1, &d2);
}
struct Data
{
int a;
float b;
PROPERTY_MAP(Data)
DECLARE_PROPERTY(a)
DECLARE_PROPERTY(b);
END_PROPERTY_MAP
};
int main()
{
Data d1, d2;
dual(d1, d2).set_a(5);
dual(d1, d2).set_b(5.7);
std::cout << d1.a << d2.a << d1.b << d2.b <<std::endl;
}
答案 4 :(得分:-1)
struct proxy {
struct column {
column(T &a, T &b);
column& operator=(T);
T &a, &b;
};
proxy(U &A, U &B);
column operator[](int i) { return column(A[i], B[i]; }
U &A, &B;
};
proxy(A, B)[0] = 5;
// or you could be evil, overload ",", and get this syntax
(A, B)[0] = 5;
或某种变异