想象一下,你有几个类,它们都包含一个具有相同含义的静态变量,但它的名称在不同的类中有所不同。
玩具示例:
class Point2D
{
public:
static constexpr int dimension = 2;
private:
double x, y;
}
class Point3D
{
public:
static constexpr int dim = 3;
private:
double x, y, z;
};
我想用std::integral_constant
的孩子包装一个“维度”变量。请注意,我无法编辑'Point'类,因为它们是某些外部库的一部分。这个实现对我有用,但看起来很笨拙(我正在使用VS2017):
template <typename T, typename = void>
struct HasDimensionVar : std::false_type { };
template <typename T>
struct HasDimensionVar<T, decltype( T::dimension, void( ) )> : std::true_type { };
template <typename T, typename = void>
struct HasDimVar : std::false_type { };
template <typename T>
struct HasDimVar<T, decltype( T::dim, void( ) )> : std::true_type { };
template <typename T, class Enable = void>
struct Dimension;
template <typename T>
struct Dimension<T, std::enable_if_t< HasDimensionVar<T>::value> > :
std::integral_constant<decltype( T::dimension ), T::dimension> { };
template <typename T>
struct Dimension<T, std::enable_if_t< HasDimVar<T>::value> > :
std::integral_constant<decltype( T::dim ), T::dim> { };
有没有办法可以跳过所有这些HasSomeVars
,并且有一些简短明了的事情:
template <typename T, class Enable = void>
struct Dimension;
template <typename T>
struct Dimension<T, decltype( T::dimension, void( ) ) > :
std::integral_constant<decltype( T::dimension ), T::dimension> { };
template <typename T>
struct Dimension<T, decltype( T::dim, void( ) ) > :
std::integral_constant<decltype( T::dim ), T::dim> { };
此代码出现编译错误:
错误C2953:'尺寸&lt; T,未知类型&gt;':类模板已经定义
答案 0 :(得分:2)
似乎虽然MSVC越来越好,但仍然有一些表达SFINAE的案例,它无法应对。所以我们只需要帮助它一点点。我们可以只提供两个不同的函数并重载它们,而不是尝试专门化同一个类模板或提供两个不同的函数,而不是:
namespace detail {
template <typename T>
constexpr std::integral_constant<decltype(T::dim), T::dim>
get_dimensions(int)
{
return {};
}
template <typename T>
constexpr std::integral_constant<decltype(T::dimension), T::dimension>
get_dimensions(long)
{
return {};
}
}
似乎MSVC似乎还不支持template<auto>
,因此您只需要重复两次名称。有了这个,我们可以使用适当的结果:
template <typename T>
using Dimension = decltype(detail::get_dimensions<T>(0));
这为我编写了关于godbolt(以及gcc和clang)的最新MSVC。
答案 1 :(得分:1)
现在......对于完全不同的事情......
您可以定义几个getDim()
模板constexpr
,启用/禁用SFINAE,功能。
一个用于dim
template <typename T>
constexpr auto getDim () -> decltype( T::dim )
{ return T::dim; }
和一个dimension
template <typename T>
constexpr auto getDim () -> decltype( T::dimension )
{ return T::dimension; }
如果需要,您可以添加其他模板功能。
现在,您的Dimension
模板类直接成为
template <typename T>
struct Dimension
: std::integral_constant<decltype(getDim<T>()), getDim<T>()>
{ };
或者,如果你想为变量赋予不同的名称
template <typename T>
struct Dimension
{
static constexpr auto dim { getDim<T>() };
};
以下是完整的编译示例
#include <iostream>
class Point2D
{
public:
static constexpr int dimension = 2;
private:
double x, y;
};
class Point3D
{
public:
static constexpr int dim = 3;
private:
double x, y, z;
};
template <typename T>
constexpr auto getDim () -> decltype( T::dim )
{ return T::dim; }
template <typename T>
constexpr auto getDim () -> decltype( T::dimension )
{ return T::dimension; }
template <typename T>
struct Dimension
: std::integral_constant<decltype(getDim<T>()), getDim<T>()>
{ };
int main()
{
Dimension<Point2D> d2; // compile
Dimension<Point3D> d3; // compile
//Dimension<int> di; // compilation error
static_assert( Dimension<Point2D>::value == 2, "!" );
static_assert( Dimension<Point3D>::value == 3, "!" );
}
答案 2 :(得分:-1)
虽然这不是一个好方法,但这对你有用:
if randint == var: