Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用(可变)模板进一步推广这一点_C++_Templates_Variadic Templates - Fatal编程技术网

C++ 如何使用(可变)模板进一步推广这一点

C++ 如何使用(可变)模板进一步推广这一点,c++,templates,variadic-templates,C++,Templates,Variadic Templates,我在模板化代码的第二步或第二级时遇到问题。为了便于阅读,我将代码精简到了最基本的部分 我已经研究了很多模板问题,但我并没有真正解决我的确切问题 我现在有一个类记录,我是这样模板化的 template <class T> class RIVRecord { private: std::vector<T> values; public: std::string name; RIVRecord(std::string _name, std::vec

我在模板化代码的第二步或第二级时遇到问题。为了便于阅读,我将代码精简到了最基本的部分

我已经研究了很多模板问题,但我并没有真正解决我的确切问题

我现在有一个类记录,我是这样模板化的

template <class T>
class RIVRecord
{

private:
    std::vector<T> values;
public:

    std::string name;

    RIVRecord(std::string _name, std::vector<T> _values) { name = _name; values = _values;  };
    ~RIVRecord(void) {  };

    size_t size() {
        return values.size();
    }

    T* Value(int index) {
        return &values[index];
    }
}
模板
课堂记录
{
私人:
std::向量值;
公众:
std::字符串名;
RIVRecord(std::string _name,std::vector _values){name=_name;values=_values;};
~RIVRecord(void){};
大小{
返回值。size();
}
T*值(整数索引){
返回值和值[索引];
}
}
很简单。T类型通常是基本类型,如浮点和整数。然后我想把这些记录放在一个DataSet类中。这是我遇到更多困难的地方。未经证实的情况是这样的:

class RIVDataSet
{
private :
    //How to template this??
    vector<RIVRecord<float>> float_records;
    vector<RIVRecord<int>> int_records;

public:
    RIVDataSet(void);
    ~RIVDataSet(void);
    //And this
    void AddRecord(RIVRecord<float> record) {
        //How would this work?    
    }
    //And this?
    RIVRecord<float> GetFloatRecord();
};
类数据集
{
私人:
//如何模板这个??
矢量浮点数记录;
向量整数记录;
公众:
数据集(无效);
~z~数据集(无效);
//还有这个
作废添加记录(RIVCORD记录){
//这是怎么回事?
}
//这个呢?
RIVRecord GetFloatRecord();
};
我来自Java背景,因此在那里我可以使用
向量
,并在询问记录时进行类型检查。但这在C++中似乎不可能。我尝试使用可变模板,但不确定如何使用模板中的所有类型构造向量:

template <class... Ts>
class RIVDataSet
{
private :        
    //For each T in Ts
    vector<RIVRecord<T>> records;

public:
    RIVDataSet(void);
    ~RIVDataSet(void);
    //For each T in Ts
    void AddRecord(RIVRecord<T> record) {
        //How would this work?    
    }
    //For each T in Ts, get the record by index.
    RIVRecord<T> GetRecord(int index);
};
模板
类数据集
{
私人:
//对于Ts中的每个T
病媒记录;
公众:
数据集(无效);
~z~数据集(无效);
//对于Ts中的每个T
作废添加记录(RIVCORD记录){
//这是怎么回事?
}
//对于Ts中的每个T,按索引获取记录。
RIVRecord GetRecord(int索引);
};
我已经看到C++模板中的这种迭代是不可能的,但它只是为了澄清我想要的。 欢迎任何帮助,谢谢

编辑:

T的类型(浮点、整数等)数量没有限制


另外,GetRecord通过有一个索引来工作,但我并不太关心它,只要我可以迭代记录并获得正确的类型

您可以使用一种称为类型擦除的技术,但是您必须包含另一个级别的间接寻址。一些一般性反馈:

RIVRecord(std::string\u名称、std::vector\u值)

最好是:

RIVRecord(常量标准::字符串和\u名称,常量标准::向量和\u值)

为了避免不必要的复制,总的来说,对于大多数非原语的东西,经验法则是接受参数为
const&

T*Value(int-index){return&values[index];}

是危险的,如果
size()
超出
向量
容量()
,它将重新分配并使所有指针无效。在我看来,一个更好的接口应该是有一个
T GetValue
&
void SetValue(tau值)

关于类型擦除,这就是
RIVDataSet
的外观,我在这里使用一个名为Loki的库,如果你不想使用Loki,我会在后面给你一些提示

class RIVDataSet
{
private :
    //How to template this??
    struct HolderBase
    {
        virtual ~HolderBase() {}
    };
    template< typename T >
    struct HolderImpl : HolderBase
    {
        // Use pointer to guarantee validity of returned record
        std::vector< RIVRecord< T >* > m_Record;
    };
    typedef Loki::AssocVector< Loki::TypeInfo, HolderBase* > HolderMap;
    HolderMap m_Records;
public:
    ~RIVDataSet() 
    { 
        for( HolderMap::iterator itrCur = m_Records.begin(); itrCur != m_Records.end(); ++itrCur ) delete itrCur->second; 
    }
    //And this
    template< typename T >
    void AddRecord(const RIVRecord< T >& record ) 
    {
        HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
        if( itrFnd == m_Records.end() )
            itrFnd = m_Records.insert( std::make_pair( Loki::TypeInfo( typeid( T ) ), new HolderImpl< T >() ) ).first;
        static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.push_back( new RIVRecord< T >( record ) );
    }
    template< typename T >
    RIVRecord< T >* GetRecord()
    {
        HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
        assert( itrFnd != m_Records.end() );
        return itrFnd == m_Records.end() ? 0 : static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.front();
    }
};
类数据集
{
私人:
//如何模板这个??
结构保持基
{
虚拟~HolderBase(){}
};
模板
结构HolderImpl:HolderBase
{
//使用指针保证返回记录的有效性
std::vector*>m_记录;
};
typedef-Loki::AssocVectorHolderMap;
持有MAP m_记录;
公众:
~RIVDataSet()
{ 
对于(HolderMap::iterator itrCur=m_Records.begin();itrCur!=m_Records.end();++itrCur)删除itrCur->second;
}
//还有这个
模板
void AddRecord(const-RIVRecord&记录)
{
迭代器itrFnd=m_Records.find(typeid(T));
if(itrFnd==m_Records.end())
itrFnd=m_记录。插入(std::make_对(Loki::TypeInfo(typeid(T)),新的HolderImpl())。首先;
静态播放(itrFnd->second)->m\u记录。向后推(新RIVRecord(记录));
}
模板
RIVRecord*GetRecord()
{
迭代器itrFnd=m_Records.find(typeid(T));
断言(itrFnd!=m_Records.end());
返回itrFnd==m_Records.end()?0:static_cast*>(itrFnd->second)->m_Record.front();
}
};

Loki::AssocVector
可以替代
std::map
,但是您确实需要
Loki::TypeInfo
,它只是
std::type\u info
的包装。如果您查看一下
Loki

中的代码,就可以很容易地自己实现一个。您不能使用可变模板来创建多个名称相同但类型不同的成员。事实上,你不可能有两个同名的成员。但是,您可以使用多重继承,并使用可变基类将成员放入基类中。然后可以在派生类中使用成员模板来解决歧义

下面的示例还使用完美转发来确保如果将临时文件传递给
add()
,其资源可能会被“窃取”。你可以阅读更多关于这方面的内容

以下是一个例子:

#include <vector>
#include <utility>

// This templated base class holds the records for each type.
template <typename T>
class Base {
    public:
        // "T &&v" is a universal reference for perfect forwarding.
        void add(T &&v) { records.push_back(std::forward<T>(v)); }
    private:
        std::vector<T> records;
};

// This inherits from Base<int>, Base<double>, for example, if you instantiate
// DataSet<int, double>.
template <typename... Ts>
class DataSet : public Base<Ts>... {
    public:
        // The purpose of this member template is to resolve ambiguity by specifying
        // which base class's add() function we want to call.  "U &&u" is a
        // universal reference for perfect forwarding.
        template <typename U>
        void add(U &&u) {
            Base<U>::add(std::forward<U>(u));
        }
};

int main() {
    DataSet<int, double> ds;
    ds.add(1);
    ds.add(3.14);
}
#包括
#包括
//此模板化基类保存每种类型的记录。
模板
阶级基础{
公众:
//“T&v”是完美转发的通用参考。
void add(T&&v){records.push_back(std::forward(v));}
私人:
病媒记录;
};
//这继承自Base,Base,例如,如果您实例化
//数据集。
模板
类数据集:公共基。。。{
公共图书馆
class BaseRIVRecord                                                                                                                                          
{                                                                                                                                                            
};                                                                                                                                                           

template <class T>                                                                                                                                           
class RIVRecord : public BaseRIVRecord                                                                                                                       
{                                                                                                                                                            
};                                                                                                                                                           

enum class RIVRecordsIndex                                                                                                                                   
{                                                                                                                                                            
   Float, Int                                                                                                                                                   
};                                                                                                                                                           

class RIVDataSet                                                                                                                                             
{                                                                                                                                                            
public:                                                                                                                                                         
    template<RIVRecordsIndex I, typename T>                                                                                                                                         
    void addRecord()                                                                                                                                
    {                                                                                                                                                            
         allmightyRecords.resize(I+1);                                                                                                                            
         allmightyRecords[I].push_back(new RIVRecord<T>());                                                                                                       
    }                                                                                                                                                            

    template<RIVRecordsIndex I, typename T>                                                                                                                                         
    RIVRecord<T>* get(unsigned int index)                                                                               
    {                                                                                                                                                            
         return static_cast<RIVRecord<T>*>(allmighyRecords[I][index]);                                                                               
    }
private:                                                                                                                                                            
    std::vector<std::vector<BaseRIVRecord*>> allmightyRecords;                                                                                                 
};                                                                                                                                                           

int main()
{
     RIVDataSet set;
     set.addRecord<RIVRecordsIndex::Float, float>();
     set.addRecord<RIVRecordsIndex::Float, float>();
     set.addRecord<RIVRecordsIndex::Int, int>();

     RIVRecord<int> r = set.get<RIVRecordsIndex::Int, int>(0);
}
template <typename... V>
class many_vectors
{
    static_assert(are_all_different<V...>::value, "All types must be different!");

    std::tuple<std::vector<V>...> _data;

public:
    template<typename T>
    std::vector<T>& data()
    { return std::get<index_of<T, V...>::value>(_data); }

    template<typename T>
    std::vector<T> const& data() const
    { return std::get<index_of<T, V...>::value>(_data); }

    template<typename T>
    void push_back(T&& arg)
    { data<typename std::remove_reference<T>::type>().push_back(std::forward<T>(arg)); }

    template<typename T, typename... W>
    void emplace_back(W&&... args)
    { data<T>().emplace_back(std::forward<W>(args)...); }
};
template<typename T, typename U, typename... V>
struct index_of : std::integral_constant<size_t, 1 + index_of<T, V...>::value>
{ };

template<typename T, typename... V>
struct index_of<T, T, V...> : std::integral_constant<size_t, 0>
{ };
template<typename T, typename... V>
struct is_different_than_all : std::integral_constant<bool, true>
{ };

template<typename T, typename U, typename... V>
struct is_different_than_all<T, U, V...>
    : std::integral_constant<bool, !std::is_same<T, U>::value && is_different_than_all<T, V...>::value>
{ };

template<typename... V>
struct are_all_different : std::integral_constant<bool, true>
{ };

template<typename T, typename... V>
struct are_all_different<T, V...>
    : std::integral_constant<bool, is_different_than_all<T, V...>::value && are_all_different<V...>::value>
{ };
v.push_back(int(3));
v.push_back<float>(4);
v.push_back<float>(5);
v.push_back(std::make_pair('a', 'b'));
v.emplace_back<std::pair<char, char>>('c', 'd');

std::cout << "ints:\n";
for(auto i : v.data<int>()) std::cout << i << "\n";

std::cout << "\n" "floats:\n";
for(auto i : v.data<float>()) std::cout << i << "\n";

std::cout << "\n" "char pairs:\n";
for(auto i : v.data<std::pair<char, char>>()) std::cout << i.first << i.second << "\n";
ints:
3

floats:
4
5

char pairs:
ab
cd