I've got a template-heavy C++ library that figures out (at compile time) how to convert between different pixel formats (i.e. convert RGB-5-6-5 to RGB-8-8-8 and such).
At its core, it isolates a pixel's individual color channels and uses a simple set of hard-coded methods to widen or narrow each channel:
template<std::size_t FromBits, std::size_t ToBits>
class UnsignedBitAdjuster;
template<>
class UnsignedBitAdjuster<5, 8> {
public: template<int TLowestSourceBitIndex, int TLowestTargetBitIndex, typename TPixel>
static constexpr TPixel Adjust(TPixel original) {
return (
BitShift<TLowestSourceBitIndex - TLowestTargetBitIndex - 3>(original) |
BitShift<TLowestSourceBitIndex - TLowestTargetBitIndex + 2>(original)
);
}
};
However, at the point of usage, GCC and clang both report the same error, whereas ICC and MSVC compile the code:
template<
PixelFormat TSourcePixelFormat, PixelFormat TTargetPixelFormat,
typename std::enable_if_t<
(TSourcePixelFormat != TTargetPixelFormat) &&
(!IsFloatFormat<TSourcePixelFormat>) &&
(!IsFloatFormat<TTargetPixelFormat>)
> * = nullptr
>
void ConvertPixel(
const PixelTypeFromFormat<TSourcePixelFormat> *sourcePixel,
PixelTypeFromFormat<TTargetPixelFormat> *targetPixel
) {
typedef LargerPixelType<TSourcePixelFormat, TTargetPixelFormat> IntermediatePixelType;
if constexpr(NeedConvertChannel1<TSourcePixelFormat, TTargetPixelFormat>) {
// This compiles
//constexpr std::size_t realMagic = 5;
// This leads to a compilation error when calling Adjuster::Adjust<0, 0>(value)
constexpr std::size_t realMagic = PixelFormatDescription<TSourcePixelFormat>::Channel1::BitCount;
constexpr std::size_t strongMagic = 4;
typedef UnsignedBitAdjuster<realMagic, strongMagic> Adjuster;
std::size_t value = 0;
std::size_t actual = Adjuster::Adjust<0, 0>(value);
}
}
The reported error is:
<source>: In function 'void Test::ConvertPixel(Test::PixelTypeFromFormat<TSourcePixelFormat>*, Test::PixelTypeFromFormat<TTargetPixelFormat>*)':
<source>:99:48: error: expected unqualified-id before numeric constant
99 | std::size_t actual = Adjuster::Adjust<0, 0>(value);
| ^
Now an unqualified-id
, as per the C++ standard, is a simple name, without a namespace in front of it, i.e. when declaring a local variable. GCC & clang seem to say that instead of the 0
, they expect such a name here?
I'm having trouble understanding what exactly drives these two compilers to take a wrong turn and so far was unable to come up with a workaround.
Maybe my code really is at fault? (ICC and MSVC compile the code cleanly).
I have uploaded a full reproduction case here: Reproduction Case on GodBolt