代码之家  ›  专栏  ›  技术社区  ›  slashmais

有没有办法使用模板来避免缩小转换范围?

  •  0
  • slashmais  · 技术社区  · 6 年前

    以下列为例:

    #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是double时,这会导致变窄。

    由于我不知道模板参数在运行时的顺序,有没有办法避免这种变窄-这样无论参数的顺序如何,in t都转换为double?

    2 回复  |  直到 6 年前
        1
  •  1
  •   jrok    6 年前

    警告来自 X 具有可变参数包。通过使用强制转换来显式地关闭编译器:

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

    这样可以消除警告, X<char> xc{2,4,6}; 我想你不介意缩小范围。

    实际避免在施工时变窄 里面 testit ,您可以使用 std::common_type :

    X< std::common_type_t<T,U> > c(b);
    
        2
  •  0
  •   Jarod42    6 年前

    要使警告静音,请显式执行强制转换:

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

    Demo