c++ - 引入typetraits后非模板的模板定义

标签 c++ templates c++17 typetraits

我有一个 ServiceLocator类(class)。它工作正常,但我想添加一个类型特征,即 ServiceLocator必须使用扩展某些 BaseService 的服务类型类(class)。我的BaseService类有一些我希望每个服务都拥有的属性,比如不可复制。那么让我们看看我的代码:

#pragma once

#include <memory>
#include <type_traits>
#include "BaseService.hpp"

template <typename T, typename std::enable_if<std::is_base_of<BaseService, T>::value>::type* = nullptr>
class ServiceLocator {
private:
    ServiceLocator() {}
    static std::unique_ptr<T> service;
public:
    static void provide(std::unique_ptr<T> service) {
        ServiceLocator::service = std::move<>(service);
    }
    static T &getService() {
        return *(ServiceLocator::service.get());
    }
};

template <typename T>
std::unique_ptr<T> ServiceLocator<T>::service;

这段代码并不那么神奇。但是我收到以下错误:

ServiceLocator.hpp:22:39: error: template definition of non-template ‘std::unique_ptr<_Tp>ServiceLocator::service’ std::unique_ptr ServiceLocator::service;

就像我说的,我的 BaseService类不是那么特别,但为了完整性:

#pragma once

#include "NonCopyable.hpp"

class BaseService : private NonCopyable {
};

不可复制:

#pragma once

class NonCopyable {
public:
    NonCopyable() {}
private:
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) = delete;
};

如果我删除模板的类型特征部分,它会起作用,所以如果我删除这部分:

, typename std::enable_if<std::is_base_of<BaseService, T>::value>::type* = nullptr

我试图制作 unique_ptr固定类型:std::unique_ptr<BaseClass>并与 static_cast 一起工作在我的两种方法中。但无法让它发挥作用。 唯一需要的是类型 T必须延长我的 BaseService .

最佳答案

It is working if i remove the typetrait part of my template, so if i remove this part:

这应该是一个关于问题的强烈提示(旁注:这不是类型特征,而是约束)。问题是,你的类模板声明是忽略默认值:

template <typename T, typename std::enable_if<std::is_base_of<BaseService, T>::value>::type*>
class ServiceLocator { ... };

也就是说,它有两个模板参数:一个类型,一个非类型。您的课外静态定义是:

template <typename T>
std::unique_ptr<T> ServiceLocator<T>::service;

这是一个模板参数。那不是一回事。您不能在此处依赖默认值,因为还需要为非默认情况定义静态成员。

这里的解决方案只是将您的约束移动到正文中 - 因为作为模板参数,我认为它不会为您解决任何问题:

template <typename T>
class ServiceLocator {
    static_assert(std::is_base_of_v<BaseService, T>);
    // ...
};

现在您只有一个模板参数,所以没问题。


请注意,在 C++11 之后,您不再需要 NonCopyable,您可以显式删除特殊成员函数:

struct BaseService {
    BaseService() = default;
    BaseService(BaseService const&) = delete;
    BaseService& operator=(BaseService const&) = delete;
};

关于c++ - 引入typetraits后非模板的模板定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49492555/

相关文章:

c++ - 为什么 C++17 结构化绑定(bind)不使用 {}?

c++ - C++ 中的链 optional

c++ - 非类名 C++11 类型名是一个简单的模板 ID?

c++ - 为什么 std::variant 不能保存数组对象类型而 union 可以?

c++ - MFC:从另一个线程调用 CWnd 方法是否安全?

c++ - 字符串复制函数产生 `pointer being freed was not allocated`

c++ - boost.Python 如何公开 boost::shared_ptr 的 typedef?

c++ - 如何将输入的数字字符串转换为 int 数组?

C++17 模板推导指南不用于空参数集?

c++ - 升压参数 : named template argument in combination with CRTP