2

Is it possible to check this:

template<class IntType,IntType value>
struct X{};

What I mean by this is, is it possible to check that value supplied by user will "fit" into IntType (which can be any of std integer types) type? For example, I would like to detect something like this:

X<char,300> a;//here 300 is out of range and I would like to be able to detect that.
phuclv
  • 37,963
  • 15
  • 156
  • 475
There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194
  • @GMan I would like to (I have to edit my OP) be able to create class of for example char and being able if user supplied correct starting value. – There is nothing we can do Apr 05 '11 at 18:33
  • 3
    @GMan: His goal is to check at compile time whether a given template parameter is within the allowable range of a given numeric type. – Lightness Races in Orbit Apr 05 '11 at 18:33
  • 1
    @There @Tomalak: Right, *why*? [What's the bigger picture?](http://www.catb.org/esr/faqs/smart-questions.html) – GManNickG Apr 05 '11 at 18:36
  • 1
    @GMan: Who cares? That's the question. – Lightness Races in Orbit Apr 05 '11 at 18:38
  • @GMan the bigger picture is that I'm playing with metaprogramming and this is one of my excersises. – There is nothing we can do Apr 05 '11 at 18:38
  • @GMan but I've to say that I agree with Tomalak, who cares? That's the question. – There is nothing we can do Apr 05 '11 at 18:40
  • 4
    @There @Tomalak: [So we can solve problems rather than answer questions.](http://jalf.dk/blog/2010/09/yes-youre-going-to-have-to-tell-me-what-your-question-is-before-i-can-answer-it/) If this was being used for some actual purpose and we knew that goal, we could take a completely different and possibly more appropriate route. Asking about the step is never as useful as asking about the goal. If someone asked "How do I resize my dynamic array?" the answer is to use a `std::vector`, not continue down the incorrect path. And you can answer in that fashion because you know the goal, not the step. – GManNickG Apr 05 '11 at 18:42
  • @GMan ok so now you know the "goal" (I've answered it in my first and second comment) and can you give the answer ? – There is nothing we can do Apr 05 '11 at 18:46
  • 5
    @GMan: I mostly disagree with "answer the problem, not the question" on Stack Overflow. It's a Q&A site, not a P&A site. If someone asks a question, answer it... don't second guess them and try to intricately inspect their motivations for doing so. (That will come naturally in the comments anyway. :P) – Lightness Races in Orbit Apr 05 '11 at 18:54
  • 1
    @There: Arguing semantics is a waste of time. If this is a goal, it's a very vapid goal without any justification present in your question. That's fine, but don't expect much effort from the answers: the solution to an imaginary problem is to stop imagining it's there. – GManNickG Apr 05 '11 at 18:55
  • 4
    @Tomalak: I disagree with a straight Q&A approach. That'd be fine if the questioner knew what they were trying to do every time, but most of the time (that is, not exceptionally), they don't. My goal is to help people, which means understanding their goals. Burying my head in the sand and acting like I don't see the real problem or better approach is only hurting people. – GManNickG Apr 05 '11 at 18:56
  • @GMan: Besides, citing that blog is as daft as [some of the articles on it](http://jalf.dk/blog/2010/08/stl-language-lawyers-and-pedantry/). :) – Lightness Races in Orbit Apr 05 '11 at 18:57
  • @GMan: Actually, over time it teaches them to ask better questions, and by extension to think more for themselves about the problem in the first place. It just takes a bit longer for them to get it, but it's way more effective than handholding. – Lightness Races in Orbit Apr 05 '11 at 18:57
  • @Tomalak: Hand-holding is more effective than not. There's a reason we have schools. – GManNickG Apr 05 '11 at 19:00
  • @GMan: Are you telling me you think typical programming education is effective? That the C++ people "learn" at schools is effective? Are you _out of your mind_? Hand-holding is the **least** effective way to teach; this is no secret! – Lightness Races in Orbit Apr 05 '11 at 19:02
  • @Tomalak: You're moving the goal post, first of all, from teaching in general to teaching programming in schools, a much narrower, more difficult, and observably broken area (are you arguing it cannot be fixed?). And that said, I'll just pile more stuff on: lectures, books, studies, journals, etc. All these are hand-holding. Do you suppose we do without them as well? – GManNickG Apr 05 '11 at 19:05
  • 1
    I don't disagree that a person who figures out all of known mathematics on their own will be enormously more capable at mathematics than someone who was taught math through schools and universities. But the former is never going to happen, we aren't capable. We have to have our hands held through the past work of others. – GManNickG Apr 05 '11 at 19:06
  • @GMan: You're the one who brought up schools (w.r.t. programming). I'm not sure how we got onto general teaching and studies/journals. Schools and universities can teach without hand-holding: programming courses in particular generally tend not to manage this. – Lightness Races in Orbit Apr 05 '11 at 19:09
  • @Tomalak: I brought up schools, but not with respect to programming. That was your own insertion. (Somewhat understandably, since our area of interest is programming, but I think understandably not my intention, as our past comments had nothing to do with programming, but about learning and teaching in general.) – GManNickG Apr 05 '11 at 19:11
  • @GMan: I figured it was automatic, since this is a _programming_ Q&A and we're talking about _programming_. – Lightness Races in Orbit Apr 05 '11 at 19:12
  • @Tomalak: Our conversion was about teaching approaches, which have no tie to programming specifically. Even if that were the case, you still have all your work ahead of you to show learning programming is somehow different from learning any other field. – GManNickG Apr 05 '11 at 19:20
  • @GMan: Lies. And I don't have to show you that programming teaching in this world is an abominable mess... or, I shouldn't. We're certainly veering down a slope of off-topicness now. – Lightness Races in Orbit Apr 05 '11 at 19:23
  • 1
    @Tomalak: I agree *many* schools teach bad programming, that doesn't mean hand-holding (books, lectures, journals, better teachers) are the wrong approach. – GManNickG Apr 05 '11 at 19:28
  • @GMan: I dispute that books, lectures, journals and the better teachers necessarily constitute hand-holding. Decent books (and the others) go out of their way to _promote individual thought_ **instead** of hand-holding. – Lightness Races in Orbit Apr 05 '11 at 19:31
  • @Tomalak: You can't promote something without holding someones hand. You cannot teach without holding hands, at some point you have to communicate a direction. – GManNickG Apr 05 '11 at 19:32
  • @GMan: I think we have different definitions of hand-holding. – Lightness Races in Orbit Apr 05 '11 at 19:35
  • @GMan: This is not a "teaching" site. We are not here to help every person with every problem that they encounter. We are here to answer interesting questions about programming languages, and _that is all_. – Lightness Races in Orbit Oct 05 '11 at 23:48
  • @TomalakGeret'kal: Who is this "we"? And I thought this discussion was dead. I care about improving understanding, you don't, that's fine. Let it go. – GManNickG Oct 06 '11 at 00:16
  • @GMan: Talk about a strawman argument. Of course I care about that. I spend several hours a day with newbies on IRC improving understanding, and _being a teacher_ somewhat helps in that regard too. This just simply isn't the appropriate place for it. I _will_ let it go seeing as you have made it apparent that you are not willing to entertain a logical discussion, instead choosing to reduce yourself to baseless personal insults. – Lightness Races in Orbit Oct 06 '11 at 00:51
  • @TomalakGeret'kal: I'm letting it go because I don't care. Really, nobody here cares what you like to do on the site or think it ought to be. – GManNickG Oct 06 '11 at 01:36
  • @GMan: Again with baseless attacks. Everybody's opinion is valid, accepted and _welcomed_ by this community. If you do not feel that this meshes with your personal mission then that's a shame – Lightness Races in Orbit Oct 06 '11 at 10:26
  • @TomalakGeret'kal: If everyone opinion is valid (which is trivially false and a terrible way to think about the world), then when you first said "@GMan: Who cares? That's the question." you contradicted yourself. I care, and by your statement you should have simply accepted my opinion on the matter, instead of challenging it (the antithesis of welcoming). Like I said, I'm done, this is my last response. – GManNickG Oct 06 '11 at 16:27
  • @GMan: I think you've taken my hyperbolic "Who cares?" to mean something that it didn't. – Lightness Races in Orbit Oct 06 '11 at 23:35
  • @GManNickG What is your goal? – Chef Gladiator Mar 04 '19 at 08:28

5 Answers5

2

Boost is the right way, but want you really want is what is coming the new C++0x standard: static asserts. Boost already implements it in boost_staticassert.

flolo
  • 15,148
  • 4
  • 32
  • 57
  • Its not that easy, but something like this should do it (warning, not checked): BOOST_STATIC_ASSERT(std::numeric_limits::max() > 300); (here you cood use instead of the numeric_limit also the boost::integer_traits stuff. – flolo Apr 05 '11 at 18:50
  • 2
    `std::numeric_limits::{max(),min()}` are not constant. Good luck using them at compile-time. – Lightness Races in Orbit Apr 05 '11 at 18:56
  • Oops, didn't see your answer. +1, this is what I just typed in. – wheaties Apr 05 '11 at 18:56
  • @Tomalak : FWIW there's [`boost::integer_traits::{const_max,const_min}`](http://www.boost.org/libs/integer/doc/html/boost_integer/traits.html) which _are_ constant expressions. – ildjarn Oct 05 '11 at 18:31
2

Now that you've changed X's signature from the way it was in the original unedited question, it's easily implemented using Boost.Integer:

#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/integer_traits.hpp>

template<
    typename IntType,
    boost::uint64_t Value,
    bool IsSigned = boost::integer_traits<IntType>::is_signed
>
struct validate_range;

template<typename IntType, boost::uint64_t Value>
struct validate_range<IntType, Value, true>
{
    typedef boost::integer_traits<IntType> traits_t;
    static bool const value =
        static_cast<boost::int64_t>(Value) >= traits_t::const_min &&
        static_cast<boost::int64_t>(Value) <= traits_t::const_max;
};

template<typename IntType, boost::uint64_t Value>
struct validate_range<IntType, Value, false>
{
    typedef boost::integer_traits<IntType> traits_t;
    static bool const value =
        Value >= traits_t::const_min &&
        Value <= traits_t::const_max;
};

template<typename IntType, boost::uint64_t Value>
struct X
{
    BOOST_STATIC_ASSERT_MSG(
        (validate_range<IntType, Value>::value),
        "Value constant is out of range"
    );
};

int main()
{
    X<char, -2> x1;             // fails iif char is unsigned by default
    X<char, 2> x2;              // fine
    X<char, 255> x3;            // fails iif char is signed by default
    X<unsigned char, -2> x4;    // fails
    X<unsigned char, 255> x5;   // fine
    X<unsigned char, 300> x6;   // fails
}
ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • The problem is that the result of converting `unsigned` to `signed` is implementation-defined, which is why I say there's no general solution. But a definite +1 for the approach. – GManNickG Apr 05 '11 at 19:21
  • @GMan : All that matters is that converting signed to unsigned to signed roundtrips the value correctly, which I believe is safe to assume in all mainstream compilers. – ildjarn Apr 05 '11 at 19:26
  • Yes, hence the +1, but it's not a general solution. – GManNickG Apr 05 '11 at 19:27
1

No. Given your code, 300 is converted to a char by the compiler before you ever get to see it.

The closest thing you can do is accept the argument into an integer parameter who's range is larger than your target type. Then check that the value will fit before converting. The only problem is signed versus unsigned, for which I don't think there's a general solution.

But not to worry: it's not your class's job to make sure the arguments are being supplied correctly; that would be the job of a utility type that simply doesn't exist. For better or for worse, C++ doesn't provide a clean mechanism for this because it assumes the programmer won't make these mistakes.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
0

I would say that the direct solution to this question might be this:

   template< typename T, T X, T L, T H>
      using inside_t = 
        std::enable_if_t< (X <= H) && (X >= L), 
           std::integral_constant<T, X> >;

Applied to the OP:

    template<typename C, unsigned K>    struct X; // final {};

template<unsigned K>
struct X<char, K> final 
{
    using ascii_ordinal = inside_t<unsigned, K, 0, 127>;
    char value = char(ascii_ordinal::value);
};

Which renders really terrible CL error messages when it does the job:

X<char, 300> a; //here 300 is out of range and I would like to be able to detect that.

While much less snazzy but most comfortable API might be:

template<unsigned K>
struct X<char, K> final 
{
    static_assert( K >= 0U && K <= 127U, "\n\nTeribly sorry, but value must be between 0 and 127 inclusive\n\n") ;
    char value = char(K);
};
E_net4
  • 27,810
  • 13
  • 101
  • 139
Chef Gladiator
  • 902
  • 11
  • 23
0

In C++20 use std::in_range

if constexpr (std::in_range<char>(300)) {
    // ...
}

There's also intcmp to do comparisons yourself

int val = 300;
if constexpr (std::cmp_greater(val, std::numeric_limits<char>::max()))
{
    std::cout << "Overflow\n";
}
else if constexpr (std::cmp_less(val, std::numeric_limits<char>::min()))
{
    std::cout << "Underflow\n";
}
else
{
    std::cout << "In range\n";
}
phuclv
  • 37,963
  • 15
  • 156
  • 475