为什么这个编译,模板扣除应该失败?

时间:2016-09-21 08:31:12

标签: c++ templates c++11

我正在尝试编写序列化程序。以下代码编译:

#include <string>
#include <fstream>
#include <type_traits>
#include <map>
#include <iostream>

class SpaceStream
{
public:

    SpaceStream(const std::string& filename)
    :
        m_file(filename)
    {
    }

    template<typename T>
    typename std::enable_if<std::is_class<T>::value>::type
    Add(const std::string& key, const T& t)
    {
        m_file << key;
        m_file << ":{";
        t.Serialise(*this);
        m_file << "},";
    }

    template<typename T>
    typename std::enable_if<!std::is_class<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value>::type
    Add(const std::string& key, const T t)
    {
        m_file << key;
        m_file << ':';
        m_file << t;
        m_file << ',';
    }

private:
    std::ofstream m_file;
    std::map<std::string,std::string> m_pointerObj;
};


class ISerialise
{
public:
    virtual void Serialise(SpaceStream& stream) const = 0;
};

class Test1 : public ISerialise
{
public:
    int m_x;
    int& m_rx;

    Test1(int& x)
    :
        m_x(x), m_rx(x)
    {
    }

    virtual void Serialise(SpaceStream& stream) const
    {
        stream.Add("x",m_x);
        stream.Add("xr",m_rx);
    }
};

int main()
{
    int j = 13;
    Test1 test(j);
    j = 23;

    SpaceStream ss("somefile.ss");
    ss.Add("testobj",test);
}

我认为这一行:

stream.Add("xr",m_rx);
由于两个Add函数,

会失败,一个专门检查类型不是一个类,另一个检查它不是一个引用。 m_rx是引用类型,因此应该失败?

修改 我现在明白,类型实际上是一个值,而不是一个引用。我需要能够识别引用,以便我可以跟踪它们(我只想将数据序列化一次,然后引用它)。

1 个答案:

答案 0 :(得分:2)

根据expr#5

  

如果表达式最初具有“对T的引用”类型([dcl.ref],[dcl.init.ref]),则在进行任何进一步分析之前将类型调整为T.表达式指定由引用表示的对象或函数,表达式是左值或x值,具体取决于表达式。 [注意:在引用的生命周期开始之前或结束之后,行为未定义(请参阅[basic.life])。 - 结束说明]

我认为参数类型(.+)*在执行模板参数推导时永远不会是引用类型。一个简单的测试可能是

A

我能想到的一个转发是使用#include <type_traits> template <class T> void f(T) { static_assert(std::is_same<T, int &>::value, "ERROR"); } template <class T> void ff(T) { static_assert(std::is_same<T, int>::value, "ERROR"); } int main(int argc, const char **argv) { int i; int &r = i; f(r); // static assert failed ff(r); // static assert success return 0; }

明确指定模板参数
decltype