function template: deducing non-type argument

I

Igor R.

Hello,

I'd like to make 2 different implementations of a function, depending
on a CT bool parameter, but the caller should not pass a template arg
explicitly:

f(true); // one implementation
f(false); // another one

Is it possible to deduce a template argument in this case?

I tried it this way:
template <bool b>
void f(bool b)
{}

It doesn't work - arg b jusst hides the template arg (MSVC9).

Thanks!
 
I

Igor R.

It's not quite what you're asking for (it involves passing a template
parameter rather than an actual parameter), but would this approach suit?

#include <iostream>

template <bool b> void f();

template <>
void f<true>()
{
        std::cout << "true version\n";

}

template <>
void f<false>()
{
        std::cout << "false version\n";

}

int main()
{
        f<true>();
        f<false>();


Well, that's trivial. The problem is that I need the template
parameter to be deduced.
 
K

Kai-Uwe Bux

Igor said:
Well, that's trivial. The problem is that I need the template
parameter to be deduced.

Deduced from what? Could you say what you want a line of client code to look
like? E.g., one could have:

f( true ) should print "true version"
f( false ) should print "false version"
f( boolean_expression_with_value_unknown_at_compile_time ) ???

I, too, am not really clear what you are looking for. In particular,

void f ( bool b ) {
if ( b ) {
std::cout << "true version";
} else {
std::cout << "false version";
}
}

is also trivial. (If the argument value is known at compile time, an
optimizing compiler could trim branches during inlining by constant
propagation.)

Please explain why the trivial options fall short.


Best

Kai-Uwe Bix
 
I

Igor R.

Ok, you're right, my question was stupid. Of course, the actual
parameter is *allowed* to be a RT value (although in my case it
isn't), and that's quite enough to disallow such an idea.

There's a function in my code:

template<typename T>
T safeUnwrap(const boost::eek:ptional<T> &t, bool throw_)
{
if (throw_ && !t)
throw EmptyOptional();
return t ? *t : T();
}

Obviously, it's good for default-constructible T only. Now there're
some non-DC types in the game, and for all of them the function is
called with throw_ == true. One of the thoughts (the stupid one) was
to use this correlation to provide another implementation of
safeUnwrap, which in turn raised the above theoretical question.

Certainly, it should be sorted out using enable_if/disable_if and the
type-trait has_nothrow_default_constructor

Thanks.
 
A

Alf P. Steinbach

* Igor R.:
Ok, you're right, my question was stupid. Of course, the actual
parameter is *allowed* to be a RT value (although in my case it
isn't), and that's quite enough to disallow such an idea.

There's a function in my code:

template<typename T>
T safeUnwrap(const boost::eek:ptional<T> &t, bool throw_)
{
if (throw_ && !t)
throw EmptyOptional();
return t ? *t : T();
}

Obviously, it's good for default-constructible T only. Now there're
some non-DC types in the game,

From later comment "DC" seems to mean "default constructible".

and for all of them the function is
called with throw_ == true.

The function above can't be called for a non-default constructible type T; it
won't compile.

Ergo, the code you're showing is not the code that your comment applies to.

This makes it difficult to help, since we're not telepathic.

One of the thoughts (the stupid one) was
to use this correlation to provide another implementation of
safeUnwrap, which in turn raised the above theoretical question.

Certainly, it should be sorted out using enable_if/disable_if and the
type-trait has_nothrow_default_constructor

What's the point of using boost::eek:ptional and translating an empty one to a T()?


Cheers & hth.,

- Alf
 
I

Igor R.

The function above can't be called for a non-default constructible type T; it
won't compile.

Sure it won't, as stated: "obviously, it's good for default-
constructible T only".
What's the point of using boost::eek:ptional and translating an empty one to a T()?

In one layer of code things are stored as optional's; another layer
should make decisions about how to treat empties.
 
P

Paul Bibbings

Igor R. said:
Hello,

I'd like to make 2 different implementations of a function, depending
on a CT bool parameter, but the caller should not pass a template arg
explicitly:

f(true); // one implementation
f(false); // another one

Is it possible to deduce a template argument in this case?

I tried it this way:
template <bool b>
void f(bool b)
{}

It doesn't work - arg b jusst hides the template arg (MSVC9).

Thanks!

A quick analysis suggests that your idea runs into the problem that a
non-type template argument must be a compile-time constant expression,
whilst the call to your proposed method provides a run-time argument.
It may be that some clever template metaprogramming might get you from
the latter to the former but, that not being my bag, I can't immediately
imagine how it might be achieved. Running through the several motifs
that do spring to mind always results in the fact that, somewhere along
the line, it will be required to specify a template argument explicitly
which, of course, merely shifts the problem without gain.

Regards

Paul Bibbings
 
A

Alf P. Steinbach

* Igor R.:
Sure it won't, as stated: "obviously, it's good for default-
constructible T only".

And in that article you wrote "Now there're some non-DC types in the game, and
for all of them the function is called with throw_ == true."

The function you showed can't be called with such type.

This is a self-contradiction.

But instead of describing existing code, which would be self-contradictory, is
that perhaps what you'd want to be possible?

I can imagine that you want e.g. ...

T const o = safeUnwrap( anOptional );

.... to throw instead of not compiling when T is not default-constructible and
anOptional is empty.

That's possible *if* you can reliably determine at compile time whether T is
default constructible or not. But it's generally not a good idea to replace
static type checking with dynamic type checking. So, best advice is, if that's
what you want to do (this is a bit unclear), don't.

to a T()?

In one layer of code things are stored as optional's; another layer
should make decisions about how to treat empties.

Uhm.


Cheers & hth.,

- Alf
 
K

Kai-Uwe Bux

Alf said:
* Igor R.:

And in that article you wrote "Now there're some non-DC types in the game,
and for all of them the function is called with throw_ == true."

The function you showed can't be called with such type.

This is a self-contradiction.
[...]

Not so fast: he did not claim that the code he posted compiles. Instead, I
think, what he is after is what should be written instead, so that it
compiles.


Best

Kai-Uwe Bux
 
J

James Kanze

Igor R. wrote:

[...]
*Deduction* is only for *types*, not values,

That's not true. I regularly use something like:

template<typename T, size_t n>
T*
end( T (&array)[n] )
{
return array + n;
}

and it works. The compiler deduces n.
and it's based on the *types* of the arguments which the
compiler knows when it sees a call to the template
instantiation (still compile-time based).

From what I gather else thread, what he really needs is two
functions, one which might return T(), and another that throws,
no matter what. The obvious solution is two different
functions.
 

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

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top