我有以下代码,由于基类没有默认的构造函数,因此我decltype()
不希望在Derived
类上获得run()
基类方法的返回类型。
class Base
{
public:
int run() { return 1; }
protected:
Base(int){}
};
struct Derived : Base
{
template <typename ...Args>
Derived(Args... args) : Base{args...}
{}
};
int main()
{
decltype(Derived{}.run()) v {10}; // it works. Not expected since
// Derived should not have default constructor
std::cout << "value: " << v << std::endl;
//decltype(Base{}.run()) v1 {10}; // does not work. Expected since
// Base does not have default constructor
//std::cout << "value: " << v1 << std::endl;
}
我知道您可以declval<>
不通过构造函数来获取成员函数,但是我的问题是为什么decltype
在这里可以工作。我试图在C ++标准中找到一些相关的东西,但没有找到任何东西。还尝试了多种编译器(gcc 5.2、7.1和clang 3.8),并且具有相同的行为。
看看不可估量的上下文和撒谎的魔力。
实际上试图做类似的事情:
Derived d;
将是一个编译错误。这是一个编译器错误,因为在评估过程中,Derived::Derived()
我们必须调用Base::Base()
不存在的。
但这是构造函数实现的细节。在评估的上下文中,我们当然需要知道这一点。但是,在未经评估的情况下,我们不需要走得太远。如果您检查std::is_constructible<Derived>::value
一下,就会发现它是true
!这是因为您可以不带参数地实例化该构造函数-因为该构造函数的实现不在该实例化的直接上下文之外。这个谎言-您可以默认构造Derived
-允许您Derived{}
在此上下文中使用,并且编译器将愉快地允许您以一种快乐的方式进行查看,这decltype(Derived{}.run())
是int
(这实际上并不涉及调用run
,因此该函数的主体同样无关紧要)。
如果您对Derived
构造函数诚实:
template <typename ...Args,
std::enable_if_t<std::is_constructible<Base, Args&...>::value, int> = 0>
Derived(Args&... args) : Base(args...) { }
然后decltype(Derived{}.run())
将无法编译,因为Derived{}
即使在未经评估的情况下,它现在仍然是格式错误的。
最好避免对编译器撒谎。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句