2017-05-05 48 views
2
#include <type_traits> 
#include <functional> 

struct Chains 
{}; 

struct Stages 
{ 

    Chains mutating_chains; 

    Chains sideffect_chains; 

    Chains write_chains; 

    void forall_chains(const std::function<void(Chains & chain)> & fun) 
    { 
     forall_chains(*this, fun); 
    } 

    void forall_chains(
     const std::function<void(const Chains & chain)> & fun) const 
    { 
     forall_chains(*this, fun); 
    } 

    template <typename Self> 
    static void forall_chains(
     Self & self, 
     const std::function<void(decltype(self.mutating_chains) & chain)> & fun) 
    { 
     fun(self.mutating_chains); 
     fun(self.sideffect_chains); 
     fun(self.write_chains); 
    } 
}; 

显然有一些我无法理解的decltype。因为根据编译器抛出的错误消息,Self被推断为const Stages,所以为什么self.member不会被推断为const成员?还有如何使它正常工作,推导const对象的const成员?我在表达式decltype((self.mutating_chains))中添加了括号,并且通过了编译,但我不确定这是否是正确的操作。decltype不会推断const对象的常量成员

f.cpp: In instantiation of ‘static void Stages::forall_chains(Self&, const std::function<void(decltype (self.mutating_chains)&)>&) [with Self = const Stages; decltype (self.mutating_chains) = Chains]’: 
f.cpp:150:33: required from here 
f.cpp:158:33: error: no match for call to ‘(const std::function<void(Chains&)>) (const Chains&)’ 
     fun(self.mutating_chains); 
+0

你可以把代码放在一个f.cpp中并编译它,它会正好抛出这个错误信息 – mkmostafa

回答

4

我加括号来表达decltype((self.mutating_chains))并通过编译,但我不知道这是做正确的事。

是的,这是在这种情况下正确的做法。简而言之,decltype(x)会给出声明的类型x,它不依赖于表达式的值类别。

对于左值表达式T类型的xdecltype((x))代替产生T&,而你的情况得到const限定符施加正确。

您可以在cppreference page for decltype(...)上找到更为正式的(和准确的)解释。


顺便说一句,请考虑通过模板参数而不是std::function通过你的回调。后者不是一个零成本的抽象 - 它是一个使用类型擦除的重量级包装,它的使用应该被最小化。

template <typename Self, typename F> 
static void forall_chains(Self& self, F&& fun){ /* ... */ } 

我写了一篇关于这个问题的文章:passing functions to functions

+1

谢谢你的回答和奖金建议:) – mkmostafa

4

是的的确的。 decltype具有用于decltype(self.mutating_chains)(重点煤矿)一种特殊情况:

如果参数是一个括号的ID-表达或的加括号的类的成员访问表达式,然后decltype产生由该表达指定的实体的类型。

因此,您将获得与self.mutating_chains已声明的实际类型,即Chains

当您添加括号,则回落到一般情况下,这实际上计算表达式,这在const Self的情况下const Chains &预期的类型:

如果参数是其他任何b)如果表达式的值类别是左值,则decltype产生T&;如果表达式的值类别是左值,则decltype产生T&;如果表达式的值类别是左值,则decltype产生T&;如果表达式的值类别是左值,则decltype产生T&;
c)[...]