2013-08-19 33 views
1

通过阅读以前的答案,我觉得我可能有设计问题,但即使答案是学术问题,我仍然想知道它是否可行。我一直在用Python编程一段时间,它显示出来了。我试图创建一个像对象setattr访问。用手它看起来像:蟒蛇般的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的版本。

+0

我想不出有任何理由使用setattr?为什么不只是'for(auto&x:foo)x.epsilon = 2.0;'? –

+0

不要试图让一种语言像另一种语言一样。那样就是徒劳。 –

+0

相关:http://stackoverflow.com/questions/5755023/why-to-use-setattr-in-python –

回答

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(); 
+0

查看** [住在Coliru](http://coliru.stacked-crooked.com/view?id=5b3f9917ae6db3bcbe4f85452a781e20-93e6c6235a92d0c233f44beab03470ad)** – sehe

+0

整洁!虽然我不完全理解模板def中的所有事情,特别是关于'remove_reference'和'forward'的部分。 – Hooked

+0

@Hooked Forwarding是什么使得它可以做到例如'set_parameter((X()),3.14,&X :: foo)',并在分配的值上享受_move semantics_。 'remove_reference'是为了帮助推导,因为对于'lvalues','T'将推断为'X&',但是'T2'_needs_是不合格的。 – sehe

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

这不会推断'T'。此外,如果您正在分配任何隐式转换,它也不会推导出“N”。 – sehe