Few minutes ago I've tried to do something like this:
#include "stdafx.h"
#include <iostream>
#include <cmath>//for pow
#include <limits>
#include <limits.h>
using std::cout;
template<class T>
struct NumericLimits;
template<>
struct NumericLimits<short>
{
enum :short {max = SHRT_MAX};
};
template开发者_C百科<short Mantissa, short Exponent, short Base = 10>
class AllocFactorScientific
{
static_assert(Mantissa > 0,"Mantissa component MUST be > zero");
//why if this works:
static_assert(Mantissa < NumericLimits<short>::max, "Provided number is too large.");
//this doesn't:
static_assert(Mantissa < NumericLimits<decltype(Mantissa)>::max, "Provided number is too large.");
private:
long double factor_;
long double calcFactor_(long int mantissa,long int exponent)
{
return mantissa * ::pow(Base,exponent);
}
public:
AllocFactorScientific():factor_(getFactor()){}
static const long double getFactor()
{
cout << "decltype(Mantissa): " << typeid(decltype(Mantissa)).name() << '\n';
return Mantissa * ::pow(static_cast<double>(Base),Exponent);
}
void setFactor(long int mantissa,long int exponent)
{
factor_ = calcFactor_(mantissa,exponent);
}
};
Please see comments in the code (just below class' name)
This is only half an answer (so feel free to half upvote it), but Google brought up a comp.std.c++ thread (initiated by litb) where the following code is being discussed :
template<int const I>
struct A
{
decltype(I) m;
};
If decltype
is legal on a non-type template parameter in this context, I believe it should be legal in yours.
Mantissa
is short
as you declared in the template, there is no need for decltype
.
If you want generic types use:
template < typename Type, Type Value >
Well, my money is on a bug. You don't mention which compiler you're using, but the stdafx suggests a variety of Visual Studio, which I don't have.
The specification says that decltype(e) should have the type of e if e is an entity. An entity is a value, object, reference, function, enumerator, type, class member, template, template specialization, namespace, parameter pack, or this. In your example, Mantissa is a prvalue by virtue of being a non-class template parameter, which, as near as I can tell is a value and therefore an entity. So, it appears that it should work, according to the spec.
I've tried your code (with minor, irrelevant modifications) in two other compilers: CodeGear RAD Studio 2010 and g++ 4.3.4. In RAD Studio, it fails to find the correct template: I get 'cannot find "max"'. If I add a "max" enum value to the base NumericLimits class, the static_assert finds that value and does a comparison.
In g++, I get internal compiler errors.
For what it's worth, you can 'launder' the type through a static variable like so:
template<short Mantissa, short Exponent, short Base = 10>
class AllocFactorScientific
{
static decltype(Mantissa) MantissaLaundry;
static_assert(Mantissa > 0,"Mantissa component MUST be > zero");
//why if this works:
static_assert(Mantissa < NumericLimits<short>::max, "Provided number is too large.");
//this works as well now:
static_assert(Mantissa < NumericLimits<decltype(MantissaLaundry)>::max, "Provided number is too large.");
private:
long double factor_;
This appears to work in RAD Studio, perhaps it will as well in Visual Studio. Alternately, you can narrow down the issue and file a bug report.
精彩评论