【问题标题】:Can't use pointer as a default template parameter不能使用指针作为默认模板参数
【发布时间】:2019-09-05 14:06:45
【问题描述】:

我正在尝试使用默认原始指针作为默认模板参数。我读到非类型模板参数仅限于整数类型、枚举、指针和引用。使用引用我没有问题,但是当我尝试使用指针时,我遇到了这样的错误:

error: non-type template argument of type 'Engine *' is not a constant expression.

这是我的代码:

#include <iostream>
#include <memory>

using std::cout;
using std::endl;

class Engine
{
public:
    void startEngine()
    {
        m_started = true;
        cout << "Engine started!" << endl;
    }
private:
    bool m_started = false;
};

template<typename T, T* DEFAULT>
class Car
{
public:
    explicit Car(const uint64_t uid) : m_uid(uid), engine(DEFAULT)
    {
        engine->startEngine();
    }

private:
    uint64_t m_uid;
    T* engine;
};

namespace
{
    std::shared_ptr<Engine> engine = std::make_shared<Engine>();
    Engine* e = engine.get();
}

int main()
{
    Car<Engine, e> lambo(0);
    return 0;
}

我现在看到的唯一限制是第二个模板参数需要具有静态存储持续时间和外部或内部链接,但代码符合这些要求。感谢任何帮助。

【问题讨论】:

  • No engine.get() 未声明返回常量。
  • @Jean-BaptisteYunès 即使它是,它仍然不会使它成为一个常量表达式。
  • @SergeyA 确定但没有被标记为它不应该被视为的标志。你说得对,我的意思是 constexpr。

标签: c++ pointers templates


【解决方案1】:

非类型模板参数必须是常量表达式:

非类型模板参数的模板参数应该是 类型的转换常量表达式 (5.20) 模板参数。


也许您可以解决此问题,使您指向的对象具有静态存储持续时间和链接 (see):

对于指向对象的指针,模板参数必须指定 具有静态存储持续时间的完整对象的地址和 链接(内部或外部),或一个常量表达式 计算为适当的空指针或 std::nullptr_t 值。

例子:

namespace{
    Engine e;
}

int main(){
    Car<Engine, &e> lambo(0);
    return 0;
}

【讨论】:

  • 谢谢,我明白了。
【解决方案2】:

与任何非类型模板参数一样,指针模板参数必须在编译时知道,或者用 C++ 标准的说法,是一个常量表达式。而且你的指针不是——编译器无法知道程序执行时这个地址是什么。

【讨论】:

    【解决方案3】:

    它不起作用,因为参数必须是常量表达式。

    因此,使用以下命令强制执行持续评估:

    namespace
    {
        Engine ee; 
    }
    
    int main()
    {
        Car<Engine, &ee> lambo(0);
    

    【讨论】:

    • 常量和常量表达式是有区别的。
    • 共享指针的东西不再使用并创建第二个实例。应该从您的示例中删除。
    • 这段代码会调用析构函数两次,产生 UB。
    猜你喜欢
    • 2011-05-25
    • 2021-11-01
    • 1970-01-01
    • 2012-10-01
    • 2023-03-13
    • 2021-04-17
    • 1970-01-01
    相关资源
    最近更新 更多