Type erasure with respect to compile-time vs. runtime parameters

K

Kevin McCarty

Hi group,

Sometimes one is in a situation where a given class could be
implemented with an integer parameter (let's say a size_t value) that
is either fixed at compile-time via a non-type template parameter, or
set at runtime via a constructor argument. The compile-time choice
gives better efficiency and lower memory usage, but only the runtime
choice is feasible if the parameter's value isn't known at compile-
time. So one may want to provide both options to clients.

I'm trying to figure out if there is any way to use some sort of type
erasure to allow clients to use the same code for the two cases. (C++
2011 perfectly ok if needed.)

Consider this pair of "skip iterator" classes:

template <typename Iter>
struct SkipIterator {
SkipIterator(Iter it, size_t skip) : it_(it), skip_(skip) { }
size_t skip() const { return skip_; }

SkipIterator & operator ++ ()
{ it_ += skip_; return *this; }
// other iterator operations

private: Iter it_; size_t skip_;
};

template <size_t Skip, typename Iter>
struct FixedSkipIterator {
FixedSkipIterator(Iter it) : it_(it) { }
static constexpr size_t skip() { return Skip; }

FixedSkipIterator & operator ++ ()
{ it_ += Skip; return *this; }
// other iterator operations

private: Iter it_;
};

Now, suppose I want to provide a function template (or a family
thereof) to make a skip iterator:

// call like: auto skipit = make_skip_iterator(it, skip);
template <typename Iter>
inline SkipIterator<Iter>
make_skip_iterator(Iter it, size_t skip)
{ return SkipIterator<Iter>(it, skip); }

// call like: auto skipit = make_skip_iterator<2>(it);
template <size_t Skip, typename Iter>
inline FixedSkipIterator<Skip, Iter>
make_skip_iterator(Iter it)
{ return FixedSkipIterator<Skip, Iter>(it); }


So finally, my question is: Is there any way to allow clients not to
need to distinguish between the above two versions of
make_skip_iterator()? That is, can they be provided with a "magical"
function template, or even a macro, named MAKE_SKIP_ITER, such that
the following code will compile and work as stated below?

array<12, unsigned char> a;
vector<unsigned char> v(12);

// These should call make_skip_iterator<4>(some_iterator);
auto it = MAKE_SKIP_ITER(a.begin(), a.size() / 3);
auto it2 = MAKE_SKIP_ITER(v.begin(), sizeof(int32_t));
auto it3 = MAKE_SKIP_ITER(v.begin(), it.skip());

// These should call make_skip_iterator(some_iterator, 4);
int skip = 4;
auto it4 = MAKE_SKIP_ITER(a.begin(), skip);
auto it5 = MAKE_SKIP_ITER(v.begin(), v.size() / 3);
auto it6 = MAKE_SKIP_ITER(a.begin(), it4.skip());

As I understand it, using a constexpr function for MAKE_SKIP_ITER()
will not work here, since constexpr functions must still be compilable
when the inputs are not compile-time constants. (And in this case,
the other function parameter, the input iterator, will never be a
compile-time constant anyway.) So that idea seems to be out...

I guess the crux of my question is, is there any way to determine at
compile-time whether a given expression is a compile-time constant
(without causing a compiler error), and use that information to switch
between two possible return values with different types, where the
fixed-compile-time case causes the expression to be used as part of
the return type. Certainly the compiler knows at compile-time whether
a given expression is a compile-time constant, but how to get at that?

All thoughts (or explanations of why this is impossible) are welcome!

Thanks,
- Kevin B. McCarty
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top