使用以下示例:
#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?
答案 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)