1

阅读以前的答案,我觉得我可能有设计问题,但即使答案是学术性的,我仍然想知道是否可能。我已经用 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 的版本。

4

2 回答 2

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";
}

哪个版画(在 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();
于 2013-08-19T21:16:24.850 回答
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);
于 2013-08-19T21:14:19.733 回答