C++ decltype不会推断常量对象的常量成员

C++ decltype不会推断常量对象的常量成员,c++,c++11,metaprogramming,C++,C++11,Metaprogramming,我在表达式decltype((self.mutating_chains))中添加了括号,并通过了编译,但我不确定这样做是否正确 #include <type_traits> #include <functional> struct Chains {}; struct Stages { Chains mutating_chains; Chains sideffect_chains; Chains write_chains; voi

我在表达式
decltype((self.mutating_chains))
中添加了括号,并通过了编译,但我不确定这样做是否正确

#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(x)
提供声明的
x
类型,它不依赖于表达式的值类别

对于类型为
T
的左值表达式
x
decltype((x))
将生成
T&
,在您的情况下,它将正确应用
常量
限定符

您可以在上找到更正式(和准确)的解释


顺便说一下,请考虑通过模板参数传递回调,而不是<代码> STD::函数< /代码>。后者不是一个零成本的抽象——它是一个使用类型擦除的重量级包装,其使用应该最小化

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);
模板
所有链的静态无效(Self&Self,F&fun){/*…*/}
我写了一篇关于这个主题的文章:。

是的,的确如此。对于
decltype(自变异链)
(强调型):

如果参数是一个未授权的id表达式或一个未授权的类成员访问表达式,则decltype将生成由该表达式命名的实体类型

因此,您得到了声明了
self.mutating_chains
的实际类型,即
chains

当添加括号时,返回到一般情况,它实际计算表达式的类型,在
const Self
的情况下,它是
const Chains&
,如预期的那样:

如果参数是类型为
T

a) […]
b) 如果表达式的值类别是左值,那么decltype将产生
T&

c) [……]


您可以将代码放入f.cpp中并编译它,它将准确地抛出此错误消息
template <typename Self, typename F>
static void forall_chains(Self& self,  F&& fun){ /* ... */ }