C ++获取模板参数包中的第一个参数值

时间:2016-07-25 18:05:44

标签: c++ c++11

我有这个班级

class AssetManager
{
private:
    std::unordered_map<const std::type_info*, Asset*> assets;

public:
    AssetManager();
    virtual ~AssetManager();

    template <typename T, typename ...Args>
    bool newAsset(Args... args)
    {   
        //Get path
        if(cached(path)) { return true; }

        auto asset = new T{ std::forward<Args>(args)... };
        assets[&typeid(*asset)] = asset;
        return *static_cast<T*>(assets[&typeid(T)]);
    }

    bool cached(const std::string& path)
    {
        for(auto asset : assets) {
          if(asset.second->getPath() == path) {
             return true;
          }
        }

        return false;
    }
};

每个Asset的第一个参数将始终是std :: string path。 我正在尝试获取此值,看看它是否已经加载到列表中。 资产是一个抽象类。

class Asset
{
private:
    std::string path;

public:
    Asset(const std::string& path);
    virtual ~Asset() = default;
    virtual bool load() = 0;
    std::string getPath();
};

继承Asset的类可能有不同数量的参数,因此我试图捕获第一个参数的值,因为它总是一个std :: string路径,你可以在Asset类构造函数中看到。

3 个答案:

答案 0 :(得分:5)

如果你的第一个参数总是一个std :: string,那么以这种方式声明是很有意义的。首先,它解决了这个问题。另一方面,它确保来电者永远不会错。如果你在资产的构造函数中也需要它,或者将它单独传递给那个构造函数,或者只是在那里声明它。

template <typename T, typename ...Args>
bool newAsset(const std::string &path, Args&&... args)
{   
    //Get path
    if(cached(path)) { return true; }

    auto asset = new T{ path, std::forward<Args>(args)... };
    assets[&typeid(*asset)] = asset;
    return *static_cast<T*>(assets[&typeid(T)]);
}

我也想知道你对typeid的使用;你绝对肯定使用它作为地图中的键是正确的吗?我没有看到任何运算符&lt;,并且运营商==无法保证根据http://en.cppreference.com/w/cpp/language/typeid(在&#39;注释&#39;)下提供一致的结果。最好使用typeid.hash_code()代替。

答案 1 :(得分:0)

  • 将路径设为必填参数,现在您可以在执行cached查找
  • 时参考该路径
  • 将路径和其他参数一起传递给Asset构造函数

template <typename T, typename ...Args>
bool newAsset(const std::string& path, Args&&... args)
{   
    if(cached(path)) { return true; }

    auto asset = new T{ path, std::forward<Args>(args)... };
    assets[&typeid(*asset)] = asset;
    return *static_cast<T*>(assets[&typeid(T)]);
}

答案 2 :(得分:0)

虽然标记的答案对于问题中描述的情况是正确的,但我最近遇到了一种情况,即不从包中拆分第一个参数会更方便。

我使用的解决方案是

template <typename... T>
void f(T&&... values)
{
   using FirstType = std::tuple_element_t<0, std::tuple<T...>>;
   ...
}

当您确实需要完全按照问题要求执行时,我将其添加到此处作为(不可否认的)案例的参考。

请注意,该函数要求至少有一个参数被调用,没有参数的调用将无法编译。