【问题标题】:How to disable instantiating a temporary class?如何禁用实例化临时类?
【发布时间】:2019-01-14 00:20:44
【问题描述】:

我正在使用一个表达式模板类,它不应该被实例化以避免悬空引用。但我很想用 auto 声明一个变量,然后“auto”创建一个临时类的命名实例。

如何在以下代码中禁用临时类的自动声明?

class Base
{
};

class Temp : public Base
{
public:
    Temp()         {}
    Temp(int, int) {}
    Temp(const Temp&) = default;
    Temp(Temp&&)      = default;
};

Temp testFunc(int a, int b) {
    return Temp{a,b};
}

int main() {
    Base a = testFunc(1,2); // this should work
    auto b = testFunc(1,2); // this should fail to compile
    return 0;
}

【问题讨论】:

  • Nitpick:Temp(const Test&)Temp(Test&&) 应该是 Temp(const Temp&)Temp(Temp&&)
  • 你也要禁止Temp a = testFunc(1,2);吗?
  • Temp a = testFunc(1,2) 应该可以工作,而 auto b = testFunc(1,2) 不应该
  • 这是不可能的。

标签: c++14 c++17 auto copy-elision deleted-functions


【解决方案1】:

您似乎想阻止用户在特定类型上使用auto。这在任何版本的 C++ 中都是不可能的。如果用户编写T t = <expr>; 是合法的C++,其中T<expr> 的类型,那么用户编写auto t = <expr>; 是合法的(忽略类数据成员)。就像您不能禁止某人使用模板参数推导将 <expr> 传递给模板函数一样。

您为阻止auto 的使用所做的任何事情也将禁止该类型的其他一些使用。

【讨论】:

  • 很高兴知道这是不可能的。但是我希望有一天控制自动成为可能,因为表达式模板非常有用,而“自动”使其容易出错。有没有不同于表达式模板的方法,可以保证省略中间prvalue构造?
【解决方案2】:

一种选择是将Temp 的构造函数设为私有,将testFunc 移动到Temp 类中并将其设为静态。这样您仍然可以实例化Base,但auto 会失败,因为您将调用私有构造函数:

class Base
{
};

class Temp : public Base
{
    Temp()         {}
    Temp(int, int) {}
    Temp(const Temp&) = default;
    Temp(Temp&&)      = default;

public:

    static Temp testFunc(int a, int b)
    {
        return Temp{a,b};
    }
};

int main() {
    Base a = Temp::testFunc(1,2); // this should work
    auto b = Temp::testFunc(1,2); // this should fail to compile
    return 0;
}

Demo

【讨论】:

  • 这到底有什么好处?你不能写Temp a = ... 的原因与auto 不起作用的原因相同。任何使用testFunc 并将结果存储在变量中的尝试都将导致切片。这有什么帮助?此外,C++17 保证的省略让您感到困惑;因为testFunc 返回一个prvalue,auto b = ... 将在有效的C++17 编译器中编译得很好。它不需要调用复制构造函数。
  • You wouldn't be able to write Temp a = ... for the same reason auto won't work 一个有效点。然而,我对这个问题的解释是,你不应该根本直接实例化Temp,但应该能够实例化Base。这一点已在最新评论中阐明。重新保证复制省略,这可能可以通过从testFunc 显式返回Temp&& 来解决,尽管在这种情况下您必须使用Temp&& c = Temp::testFunc(1,2) 获取实例,这可能并不理想。
  • 您不能返回对堆栈变量的引用。
  • 嗯,是的,我一直没想到。
猜你喜欢
  • 2011-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2010-09-10
相关资源
最近更新 更多