考虑以下示例(我今天发布了几个不同的问题):
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
// Version A
template<typename T>
constexpr unsigned int f(const T&)
{
return 1;
}
// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f(const T<T1...>&)
{
return 2;
}
// Version C
template<typename T1, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f(const T<T1, N...>&)
{
return 3;
}
// Main
int main(int argc, char* argv[])
{
std::integral_constant<int, f(double())> a;
std::integral_constant<int, f(std::vector<double>())> b;
std::integral_constant<int, f(std::array<double, 3>())> c;
std::cout<<a<<b<<c<<std::endl; // The goal is to return 123
return 0;
}
此代码无法编译并返回以下编译错误:
temporary of non-literal type 'std::vector<double>' in a constant expression
如何修改此代码以进行编译?
注意:目标是将函数的第一个版本将采用的类型转换为1,将函数的第二个版本采用的类型转换为2,等等...
答案 0 :(得分:1)
定义常量时不能使用临时向量:
int main(int argc, char* argv[])
{
std::integral_constant<int, f(double())> a;
std::vector<double> vec;
std::integral_constant<int, f(vec)> b;
std::integral_constant<int, f(std::array<double, 3>())> c;
std::cout << a << b << c;
return 0;
}
问题是编译器可能会省略vector
创建,如果vector的唯一目的是传递给常量表达式函数,但实际上它不能,因为vector不是文字类型。
std::array
只是c数组上面的包装器,它有简单的构造函数和析构函数。由于double也是文字类型,因此双精度数组变为字面值。
但请注意,如果您定义
struct A
{
A(){std::cout << "I'm so complicated A!\n"; }
}
你将无法使用构造:
int main(int argc, char* argv[])
{
std::integral_constant<int, f(A())> a;
std::integral_constant<int, f(std::array<A, 3>())> c;
std::cout << a << b << c;
return 0;
}
,或者
int main(int argc, char* argv[])
{
A a_v;
std::integral_constant<int, f(a_v)> a;
std::array<A, 3> c_v
std::integral_constant<int, f(c_v)> c;
std::cout << a << b << c;
return 0;
}
仍然是可能的。
答案 1 :(得分:1)
你需要在函数上不可能进行部分特化,将它们包装在struct / class中完成工作:
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
// Version A
template<typename T>
struct f
{
constexpr static unsigned int execute()
{
return 1;
}
};
// Version B
template<template <typename ... > class Tpl, typename ... TplArgs>
struct f< Tpl<TplArgs...> >
{
constexpr static unsigned int execute()
{
return 2;
}
};
// Version C
template<template<typename, std::size_t...> class Tpl, typename FirstArg, std::size_t... N>
struct f< Tpl<FirstArg, N...> >
{
constexpr static unsigned int execute()
{
return 3;
}
};
// Main
int main(int argc, char* argv[])
{
std::integral_constant<int, f<double>::execute()> a;
std::integral_constant<int, f<std::vector<double>>::execute()> b;
std::integral_constant<int, f<std::array<double, 3>>::execute()> c;
std::cout << a << ' ' << b << ' ' << c << std::endl;
return 0;
}
答案 2 :(得分:0)
您的问题是我们可以承受多少修改此代码?例如,以下编译,但你正在尝试做什么?
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
// Version A
template<typename T>
constexpr unsigned int f()
{
return 1;
}
// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f()
{
return 2;
}
// Version C
template<typename T1 = double, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f()
{
return 3;
}
// Main
int main(int argc, char* argv[])
{
std::integral_constant<int, f<double>()> a;
std::integral_constant<int, f<std::vector<double>>()> b;
std::integral_constant<int, f<std::array<double, 3>>()> c;
return 0;
}
答案 3 :(得分:0)
我通过使用指针代替引用找到了解决方案:
// Version A
template<typename T>
constexpr unsigned int f(const T*)
{
return 1;
}
// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f(const T<T1...>*)
{
return 2;
}
// Version C
template<typename T1, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f(const T<T1, N...>*)
{
return 3;
}
// Main
int main(int argc, char* argv[])
{
std::vector<double> tmp;
std::integral_constant<int, f(static_cast<double*>(nullptr))> a;
std::integral_constant<int, f(static_cast<decltype(tmp)*>(nullptr))> b;
std::integral_constant<int, f(static_cast<std::array<double, 3>*>(nullptr)) > c;
std::cout<<a<<b<<c<<std::endl;
return 0;
}
也许这不是最优雅的方式,但它有效。如果某人有一个优雅的相当于此,我很感兴趣。