decltype 不推导 const 对象的 const 成员
decltype does not deduce const members for const objects
#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 阶段,那么为什么 self.member 没有被推导为 const 成员呢?还有如何让它正常工作,为 const 对象推导出 const 成员?我在表达式 decltype((self.mutating_chains))
中添加了括号并通过了编译,但我不确定这样做是否正确。
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);
I added parenthesis to the expression decltype((self.mutating_chains))
and that passed compilation but I'm not sure if that is the correct thing to do.
是的,在这种情况下这是正确的做法。简而言之,decltype(x)
为您提供 声明的类型 x
,它不依赖于表达式的值类别。
对于类型为 T
的 左值表达式 x
,decltype((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。
是的,的确如此。 decltype
有一个 decltype(self.mutating_chains)
的特例(强调我的):
If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression.
所以你得到了声明 self.mutating_chains
的实际类型,即 Chains
.
当你添加括号时,你又回到了一般情况,它实际上评估了表达式的类型,在 const Self
的情况下,如预期的那样是 const Chains &
:
If the argument is any other expression of type T
, and
a) [...]
b) if the value category of expression is lvalue, then decltype yields T&
;
c) [...]
#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 阶段,那么为什么 self.member 没有被推导为 const 成员呢?还有如何让它正常工作,为 const 对象推导出 const 成员?我在表达式 decltype((self.mutating_chains))
中添加了括号并通过了编译,但我不确定这样做是否正确。
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);
I added parenthesis to the expression
decltype((self.mutating_chains))
and that passed compilation but I'm not sure if that is the correct thing to do.
是的,在这种情况下这是正确的做法。简而言之,decltype(x)
为您提供 声明的类型 x
,它不依赖于表达式的值类别。
对于类型为 T
的 左值表达式 x
,decltype((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。
是的,的确如此。 decltype
有一个 decltype(self.mutating_chains)
的特例(强调我的):
If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression.
所以你得到了声明 self.mutating_chains
的实际类型,即 Chains
.
当你添加括号时,你又回到了一般情况,它实际上评估了表达式的类型,在 const Self
的情况下,如预期的那样是 const Chains &
:
If the argument is any other expression of type
T
, and
a) [...]
b) if the value category of expression is lvalue, then decltype yieldsT&
;
c) [...]