模板化一个类似python的setattr函数

Template a python-like setattr function

本文关键字:python 函数 setattr 一个      更新时间:2023-10-16

通读以前的答案,我觉得我可能有设计问题,但即使答案是学术性的,我仍然想知道这是否可能。我用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函数。虽然我确信boost可以做到这一点,但如果可能的话,我更希望看到STL版本。

更新:

Oops原来我错过了在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";
}

哪个打印(在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();

您可能可以使用指向成员的指针,但我不确定您是否会喜欢:

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);