可变参数模板化构造函数不接受 x 参数

Variadic templated constructor does not take x arguments

本文关键字:参数 构造函数 不接受 变参      更新时间:2023-10-16

对于模板化类的内部模板化结构,我想要一个可变参数化构造函数。不幸的是,构造函数(请参阅下面的第一个构造函数(是不够的:如果我只使用该构造函数,我会收到 C2260 编译器错误,指出构造函数不接受 3、4 或 5 个参数。另一方面,通过添加另外三个构造函数(请参阅下面的其余构造函数(使所有内容都显式化,按预期工作。

template< typename KeyT, typename ResourceT >
class ResourcePool {
    ...
    template< typename DerivedResourceT >
    struct ResourcePoolEntry final : public DerivedResourceT {
        template< typename... ConstructorArgsT >
        ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ConstructorArgsT... args)
            : DerivedResourceT(args...), m_resource_pool(resource_pool), m_resource_key(resource_key) {}
        ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ID3D11Device2 &x)
            : DerivedResourceT(x), m_resource_pool(resource_pool), m_resource_key(resource_key) {}
        
        ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ID3D11Device2 &x, const wstring &y)
            : DerivedResourceT(x,y), m_resource_pool(resource_pool), m_resource_key(resource_key) {}
        
        template < typename VertexT >
        ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ID3D11Device2 &x, const wstring &y, const MeshDescriptor< VertexT > &z)
            : DerivedResourceT(x, y, z), m_resource_pool(resource_pool), m_resource_key(resource_key) {}
           ...
    }
}

构造函数的调用方式如下:

template< typename KeyT, typename ResourceT >
template< typename... ConstructorArgsT >
std::shared_ptr< ResourceT > ResourcePool< KeyT, ResourceT >::GetResource(KeyT key, ConstructorArgsT... args) {
    return GetDerivedResource< ResourceT, ConstructorArgsT... >(key, args...);
}
template< typename KeyT, typename ResourceT >
template< typename DerivedResourceT, typename... ConstructorArgsT >
std::shared_ptr< ResourceT > ResourcePool< KeyT, ResourceT >::GetDerivedResource(KeyT key, ConstructorArgsT... args) {
    ...
    auto new_resource = std::shared_ptr< ResourcePoolEntry< DerivedResourceT > >(
        new ResourcePoolEntry< DerivedResourceT >(*this, key, args...));
    ...
}

对于像bool这样的原语作为可变参数,一切正常。

Severity    Code    Description Project File    Line    Suppression State
Error   C2660       'mage::ResourcePool<std::wstring,mage::VertexShader>::ResourcePoolEntry<DerivedResourceT>::ResourcePoolEntry': function does not take 3 arguments   MAGE    c:usersmatthiasdocumentsvisual studio 2015projectsmagemagemagesrcresourceresource_pool.tpp   37

其中第 37 行对应于构造函数调用(在上面的示例中new ResourcePoolEntry< DerivedResourceT >(*this, key, args...));(

我做错了什么?(编译器 MSVC++ 14.0(

最小示例:

#include <memory>
#include <map>
template < typename T >
using SharedPtr = std::shared_ptr< T >;
template < typename T >
using WeakPtr = std::weak_ptr< T >;
template< typename KeyT, typename ResourceT >
using ResourceMap = std::map< KeyT, WeakPtr< ResourceT > >;
template< typename KeyT, typename ResourceT >
class ResourcePool {
public:
    template< typename... ConstructorArgsT >
    SharedPtr< ResourceT > GetResource(KeyT key, ConstructorArgsT... args);
    template< typename DerivedResourceT, typename... ConstructorArgsT >
    SharedPtr< ResourceT > GetDerivedResource(KeyT key, ConstructorArgsT... args);
        
private:
    ResourceMap< KeyT, ResourceT > m_resource_map;
    template< typename DerivedResourceT >
    struct ResourcePoolEntry final : public DerivedResourceT {
    public:
        template< typename... ConstructorArgsT >
        ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ConstructorArgsT... args)
            : DerivedResourceT(args...), m_resource_pool(resource_pool), m_resource_key(resource_key) {}
    private:
        ResourcePool< KeyT, ResourceT > &m_resource_pool;
        KeyT m_resource_key;
    };
};
template< typename KeyT, typename ResourceT >
template< typename... ConstructorArgsT >
SharedPtr< ResourceT > ResourcePool< KeyT, ResourceT >::GetResource(KeyT key, ConstructorArgsT... args) {
    return GetDerivedResource< ResourceT, ConstructorArgsT... >(key, args...);
}
template< typename KeyT, typename ResourceT >
template< typename DerivedResourceT, typename... ConstructorArgsT >
SharedPtr< ResourceT > ResourcePool< KeyT, ResourceT >::GetDerivedResource(KeyT key, ConstructorArgsT... args) {
    auto it = m_resource_map.find(key);
    if (it != m_resource_map.end()) {
        auto resource = it->second.lock();
        if (resource) {
            return resource;
        }
        else {
            m_resource_map.erase(it);
        }
    }
    auto new_resource = SharedPtr< ResourcePoolEntry< DerivedResourceT > >(
        new ResourcePoolEntry< DerivedResourceT >(*this, key, args...));
    m_resource_map[key] = new_resource;
    return new_resource;
}
#include <d3d11_2.h>
struct A {
};
struct B : public A {
    B(ID3D11Device &device) : A() {}
};

const D3D_FEATURE_LEVEL g_feature_levels[] = {
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0
};
int main() {
    ID3D11Device *device;
    ID3D11DeviceContext *device_context;
    D3D_FEATURE_LEVEL feature_level;
    D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, 
        g_feature_levels, _countof(g_feature_levels), D3D11_SDK_VERSION,
        &device, &feature_level, &device_context
    );
    ResourcePool< char, A > *pool = new ResourcePool< char, A >();
    //pool->template GetResource< int & >('a');
    pool->template GetDerivedResource< B, ID3D11Device & >('b', *device);
}

错误

Severity    Code    Description Line    Suppression State
Error   C2661   'ResourcePool<char,A>::ResourcePoolEntry<DerivedResourceT>::ResourcePoolEntry': no overloaded function takes 3 arguments    66

需要注意的一件事(这可能是也可能不是问题的最终原因(是您在模板参数转发方面做得不对。例如,在你传递ID3D11Device2的情况下,你的DerivedResourceT构造函数可能(从你的非可变参数构造函数的签名判断(需要一个引用 - 但是由于模板推导的工作方式,它实际上会得到一个副本(如果这确实是允许的 - 如果不是,它不会编译(。

要更正此问题,您需要使用标准转发配方,它允许传递传递参数的正确 l 值或 r 值,其中包括正确转发引用:

template< typename... ConstructorArgsT >
ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool,
            KeyT resource_key, ConstructorArgsT&&... args)
            : DerivedResourceT(std::forward<ConstructorArgsT>(args)...), m_resource_pool(resource_pool), m_resource_key(resource_key) {}

在上面,请注意参数类型中的&& args...std::forward调用。