模板类似python的setattr函数

时间:2013-08-19 21:01:13

标签: c++ templates c++11 stl

通过以前的答案,我觉得我可能有设计问题,但即使答案是学术性的,我仍然想知道是否有可能。我已经用Python编程了一段时间,它显示了。我正在尝试在对象上创建类似setattr访问权限的内容。用手看起来像:

template<class T, class U>
void set_parameter_sigma(T &S, U val) {
  for(auto &x: S) { x.sigma = val; }
}

template<class T, class U>
void set_parameter_epsilon(T &S, U val) {
  for(auto &x: S) { x.epsilon = val; }
}

template<class T, class U>
void set_parameter_length(T &S, U val) {
  for(auto &x: S) { x.length = val; }
}

我想要的是看起来像下面的伪代码:

template<class T, class U, class N>
void set_parameter(T &S, U val) {
  for(auto &x: S) { x.N = val; }
}

我可以像set_parameter(foo, 2.0, "epsilon")一样调用它,编译器会自动创建set_parameter_epsilon函数。虽然我确信提升可以做到这一点,但如果可能的话,我更愿意看到仅限STL的版本。

2 个答案:

答案 0 :(得分:5)

更新

哎呀原来我错过了要求来循环setter中的容器元素。那么,让我修改我的错误:

#include <utility>

template <class C, class U, class U2 /* assignable from U*/, 
    class T = typename C::value_type>
   void set_parameter(C& container, U&& val, U2 (T::* pmember), typename C::value_type* sfinae=nullptr)
{
    for (auto& instance : container)
        (instance.*(pmember)) = std::forward<U>(val);
}

#include <iostream>
#include <string>
#include <vector>

struct X
{
    double foo;
    std::string splurgle;
};

int main()
{
    std::vector<X> xs(10);

    set_parameter(xs, 42, &X::foo);
    set_parameter(xs, "hello world", &X::splurgle);

    for (auto const& x : xs)
        std::cout << x.foo << ", " << x.splurgle << "\n";
}

打印哪些内容( Live on Coliru

42, hello world
42, hello world
42, hello world
42, hello world
42, hello world
42, hello world
42, hello world
42, hello world
42, hello world
42, hello world

原始答案文字:

#include <utility>
#include <type_traits>

template <class T, class U, class U2 /* assignable from U*/, class T2 = typename std::remove_reference<T>::type>
   T&& set_parameter(T&& instance, U&& val, U2 (T2::* pmember))
{
    (instance.*(pmember)) = std::forward<U>(val);
    return std::forward<T>(instance);
}

这充满了细微差别。但足以说,它按照要求“有效”:

#include <iostream>
#include <string>
struct X
{
    double foo;
    std::string splurgle;
};

int main()
{
    X x;

    set_parameter(x, 3.14         , &X::foo);
    set_parameter(x, "hello world", &X::splurgle);

    std::cout << x.foo << ", " << x.splurgle;
}

输出:

3.14, hello world

增加精神错乱:请注意,通过返回有用的值,您可以做更多...有趣的事情,仍然:

return set_parameter(
        set_parameter(X(), 3.14, &X::foo),
        "hello world", &X::splurgle)
    .splurgle.length();

答案 1 :(得分:0)

你可能可以使用指向成员的指针,但我不确定你是否会这样:

struct XX
{
    char c;
    int i;
};


template<class T, class U, class N>
void set_parameter(T &S, U val, N T::*n) {
  for(auto &x: S) { x.*n = val; }
}

set_parameter(..., ..., &XX::c);
set_parameter(..., ..., &XX::i);