有没有一种使用模板的方法来避免缩小转换范围?

时间:2019-01-01 08:15:53

标签: c++ templates

使用以下示例:

#include <iostream>
#include <vector>
#include <type_traits>

template<typename T>struct X
{
    std::vector<T> v;
    void clear() { v.clear(); }
    ~X(){}
    X(){ clear(); }
    X(const X &x) { v=x.v; }
    //template<typename ...I> X(I...i) : v({static_cast<T>(i)...}) {} //<---gets rid of warnings only, still narrowing
    template<typename ...I> X(I...i) : v({i...}) {}
    template<typename U> X(const U &u) { for (auto e:u.v) v.push_back((T)e); }

    bool operator==(const X &x) const { return (v==x.v); }
    template<typename U> bool operator==(const U &u) { X<T> x(u); return (v==x.v); }

    void show(const std::string &s) const
    {
        using TYPE=typename std::common_type<T,int>::type;
        std::cout << s << " = ";
        for (auto x:v) std::cout << (TYPE)x << " ";
        std::cout << "\n";
    }
};

template<typename T> bool testit(const T a, const T b)
{
    return (a==b);
}

template<typename T> bool testit(const X<T> a, const X<T> b)
{
    return (a==b);
}

template<typename T, typename U> bool testit(const X<T> a, const X<U> b)
{
    X<T> c(b); // this is the problem - t=int, U=double => narrowing
    return testit(a, c);

/*
    // tried doesn't work

    if (sizeof(decltype(T()))<sizeof(decltype(U())))
    {
        X<U> c(a);
        X<U> d(b);
        return testit(c,d);
    }
    else
    {
        X<T> c(a);
        X<T> d(b);
        return testit(c,d);
    }
*/

/*
    //doing the following causes a segfault -- I have no idea why

    using T1=typename std::common_type<T, int>::type;
    using T2=typename std::common_type<U, int>::type;
    using TT=typename std::common_type<T1, T2>::type;
    X<TT> c(a);
    X<TT> d(b);
    return testit(d,b);
*/

}


int main(int argc, const char *argv[])
{
    auto res=[](bool b)->std::string{ return b?"OK":"Fail"; };
    auto test=[res](const std::string s, bool btest, bool bexp){ std::cout << s << " - " << res(btest==bexp) << "\n"; };

    test("(1,1)", testit(1,1), 1);
    test("(1,2)", testit(1,2), 0);
    test("(abc,abc)", testit("abc","abc"), 1);
    test("(abc,aaa)", testit("abc","aaa"), 0);

    X<int> xa{1,2,3};               xa.show("xa");
    X<double> xb{1.0, 2.0, 3.0};    xb.show("xb");
    X<char> xc{2,4,6};              xc.show("xc");
    X<double> xd{1.1, 2.1, 3.1};    xd.show("xd");


    test("(xa, xb)", testit(xa,xb), 1);
    test("(xa, xc)", testit(xa,xc), 0);
    test("(xb, xc)", testit(xb,xc), 0);

    test("(xc, {2.0, 4.0, 6.0})", testit(xc, {2.0, 4.0, 6.0}), 1);
    test("(xc, {2.0, 4.1, 6.0})", testit(xc, {2.0, 4.1, 6.0}), 0);

    test("(X<int>({4, 5, 6}), {4.0, 5.0, 6.0})", testit(X<int>({4, 5, 6}), {4.0, 5.0, 6.0}), 1);
    test("(X<int>({4, 5, 6}), {4.0, 5.0, 6.1})", testit(X<int>({4, 5, 6}), {4.0, 5.0, 6.1}), 0);

    return 0;
}

当T为int且U为双精度时会导致变窄。

由于我不知道模板参数在运行时的顺序,因此有没有一种方法可以避免这种变窄-不管参数的顺序如何,都将int转换为double?

2 个答案:

答案 0 :(得分:1)

警告来自带有可变参数包的X的一个构造函数。您可以通过强制转换来使编译器保持沉默:

template<typename ...I> X(I...i) : v({static_cast<T>(i)...}) {}

这摆脱了X<char> xc{2,4,6};发出的警告,我认为您不介意缩小范围。

X内构造testit时,实际上避免了缩小,您可以使用std::common_type

X< std::common_type_t<T,U> > c(b);

答案 1 :(得分:0)

要使警告静音,请明确进行强制转换:

template<typename ...I> X(I...i) : v({static_cast<T>(i)...}) {}

Demo