我有一些代码使用两种不同类型的颜色,每通道8位,每通道16位,每个由结构表示。为了有效地重用我的代码,我有一个模板函数,可以用它们进行一些渲染。因此,我想要一个模板化的函数来获取我的颜色通道的最大值。
我最初的尝试看起来像这样。我只展示了8 bpc
的专业化struct Pixel8
{
unsigned char r;
unsigned char g;
unsigned char b;
};
#define PIXEL8_MAX 255
template <class PIXEL>
auto getMax( ) -> decltype( PIXEL::r )
{
static_assert( sizeof(PIXEL) > 0, "getMax can only be called with a pixel type." );
}
template <>
auto getMax<Pixel8>( ) -> decltype( Pixel8::r )
{
return PIXEL8_MAX;
}
这不能用Visual Studio 2012编译。我收到错误
1&GT;错误C2785:''unknown-type'getMax(void)'和'char getMax(void)'有不同的返回类型 1 GT;看到'getMax'的声明
对我来说,我觉得这应该有效,但我找不到任何例子。在Specialize function template with decltype trailing return type还有一个类似的问题,但是这里的返回类型对于每个专业化都是相同的。
我找到了一个解决方法,我将其作为答案发布,以便其他人可以受益。但是它不是很透明,所以如果有人能告诉我上面的代码是否有效且这是VC ++不兼容还是无效,那么为什么以及如何使其有效呢?
答案 0 :(得分:0)
这是获取所需行为的解决方法。它依赖于以下事实:在不使用decltype的情况下,还有另一种在C ++中定义类型的方法。这是使用typname。
在这种情况下它的主要用途如下,想象两个类和两个函数
class MyClass
{
public:
class MyThing
{
};
};
class MyOtherClass
{
public:
static int MyThing;
}
template< class T >
void func1( T something )
{
typename T::MyThing thing;
}
template< class T >
void func2( T something )
{
T::MyThing = 5;
}
如果我们将任一类作为模板参数T传递,那么T :: MyThing将是MyClass的类型,而MyOtherClass是静态int。这些完全不兼容,因此我们使用typename来分隔它们。 在func1中,我们使用typename来声明T :: MyThing是一个类型。我们可以传入一个MyClass对象。在func2中我们省略了typename,因此T :: MyThing被解释为变量,我们可以传入MyOtherClass。如果没有typename,就无法判断T :: MyThing是类型还是静态变量。
另请注意,typename可以引用typdef以及内部类。因此,如果我们创建一个模板化的类或包含类型的typedef的结构,我们可以使用typename访问该类型。
template<class PIXEL>
struct pixTypes
{
};
template<>
struct pixTypes<Pixel8>
{
typedef char type;
};
template <class PIXEL>
auto getMax( ) -> typename pixTypes<PIXEL>::type
{
static_assert( false, "getMax can only be called with a pixel type." );
}
template <>
auto getMax<Pixel8>() -> typename pixTypes<Pixel8>::type
{
return PIXEL8_MAX;
}
所以现在我们从一个typename中获取我们的返回类型,该类型引用一个专门模板化结构中的typedef。
这似乎是一种围绕一切的复杂方式,但它确实在Visual Studio 12上编译。
答案 1 :(得分:0)
尝试使返回类型取决于模板参数类型:
struct Pixel8
{
char r;
char g;
char b;
};
template<typename T>
struct ColourType
{
typedef decltype(T::r) type;
};
#define PIXEL8_MAX 255
template <class PIXEL>
typename ColourType<PIXEL>::type getMax()
{
static_assert(false, "getMax can only be called with a pixel type.");
}
template <>
ColourType<Pixel8>::type getMax<Pixel8>()
{
return PIXEL8_MAX;
}
答案 2 :(得分:0)
使用宏来定义常量,如本问题的代码
#define PIXEL8_MAX 255
......不理想。
此外,定义与使用的类型冲突。 char
不保证具有该最大值,并且大多数实现默认情况下不具有该最大值。您可以将Byte
类型定义为unsigned char
,但即使如此,您也不能保证8位,并且应该检查它。
标准库提供 numeric_limits
类模板来处理最大值等。:
#include <limits> // std::numeric_limits
#define STATIC_ASSERT( e ) static_assert( e, #e )
using Byte = unsigned char;
int const bits_per_byte = std::numeric_limits<Byte>::digits;
STATIC_ASSERT( bits_per_byte == 8 );
struct Pixel8
{
Byte r;
Byte g;
Byte b;
};
template< class Pixel >
constexpr auto getMax() -> decltype( Pixel::r )
{
return std::numeric_limits<decltype( Pixel::r )>::max();
}
#include <iostream>
using namespace std;
auto main() -> int
{
cout << +getMax<Pixel8>() << endl;
}