Any way to defer template function overloading?

Q

Qi

Let me show some test code.

=====code start

template <typename T>
void abc(const T &)
{
cout << "1" << endl;
}

template <typename T>
void test(const T & a)
{
abc(a);
}

void abc(const string &)
{
cout << "2" << endl;
}

int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

string s;
test(s);

return 0;
}

=====code end

"abc" is a template function that I use as some kind of traits.
(similar as get_pointer in Boost).
The "string" overloading is after the "test" function.

"test" is the function where using "abc". "test" is a template
function too.

"main" is the function that using "test". It's guaranteed that
all overloading will be declared before main (but may after "test").

In standard way, above code will print "1" on GCC (VC will print "2"
because of its less standard template parsing).

My question is, is there any way to make "test" chooses
the "string" overloading and print 2, no matter the overloading
is before or after "test"?

The reason I want that is, the overloading functions may spread
in multiple headers, if "test" can only choose the overloading
that declared before it, that will enforce the including order of
the headers.


Thanks
 
I

Ian Collins

Let me show some test code.

=====code start

template<typename T>
void abc(const T&)
{
cout<< "1"<< endl;
}

template<typename T>
void test(const T& a)
{
abc(a);
}

void abc(const string&)
{
cout<< "2"<< endl;
}

int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

Why do this?
string s;
test(s);

return 0;
}

=====code end

"abc" is a template function that I use as some kind of traits.
(similar as get_pointer in Boost).
The "string" overloading is after the "test" function.

"test" is the function where using "abc". "test" is a template
function too.

"main" is the function that using "test". It's guaranteed that
all overloading will be declared before main (but may after "test").

In standard way, above code will print "1" on GCC (VC will print "2"
because of its less standard template parsing).

My question is, is there any way to make "test" chooses
the "string" overloading and print 2, no matter the overloading
is before or after "test"?

Make the function a specialisation:

template <>
void abc(const std::string&)
{
std::cout << "2" << std::endl;
}
 
Q

Qi

Make the function a specialisation:

template <>
void abc(const std::string&)
{
std::cout << "2" << std::endl;
}

Awesome, it works perfectly. Thanks.

Can I understand that as, the specialization is solved
at the second pass of template parsing, while the overloading
is solved at the first pass?

However, here has some discussion on the risk to use
template function specialization
http://www.gotw.ca/publications/mill17.htm

Seems the class specialization way is better and safer. :)
 
J

Juha Nieminen

Qi said:
int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

This seemed like nonsensical code because it does nothing. Then I realized
that it's an ugly hack to silence the compiler warning about unused
variables. That's not how you do it.

The proper way of getting rid of the warnings is to not name the
parameters. If you still want to have their names visible, you can
simply comment them out:

int main(int /*argc, char** /*argv*/)
{
...
}

Incidentally, main() doesn't need parameters, so you can just omit them:

int main()
{
...
}
 
A

Alf P. Steinbach

Qi said:
int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

This seemed like nonsensical code because it does nothing. Then I realized
that it's an ugly hack to silence the compiler warning about unused
variables. That's not how you do it.

Right. I used to advocate a function template for that. But now I'd
rather use a macro, e.g. like this:


<code>
#if !defined( CPP_DECLARE_UNUSED )
# define CPP_DECLARE_UNUSED( argName ) \
(void)(argName, void(), 0); struct argName; (void)0
#endif
// SO user sehe: "(void)0" for semicolon
// SO user R. Martinho Fernandes, pointed out operator void() problem
// SO user Johannes Schaub, solution to operator,() problem
The proper way of getting rid of the warnings is to not name the
parameters. If you still want to have their names visible, you can
simply comment them out:

int main(int /*argc, char** /*argv*/)

But the names have documentary value, and those comments do not nest,
e.g. for the purpose of commenting out code.

{
...
}

Incidentally, main() doesn't need parameters, so you can just omit them:

int main()
{
...
}

Yes. :)


Cheers,

- Alf
 
I

Ian Collins

Qi said:
int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

This seemed like nonsensical code because it does nothing. Then I realized
that it's an ugly hack to silence the compiler warning about unused
variables. That's not how you do it.

Right. I used to advocate a function template for that. But now I'd
rather use a macro, e.g. like this:


<code>
#if !defined( CPP_DECLARE_UNUSED )
# define CPP_DECLARE_UNUSED( argName ) \
(void)(argName, void(), 0); struct argName; (void)0
#endif
// SO user sehe: "(void)0" for semicolon
// SO user R. Martinho Fernandes, pointed out operator void() problem
// SO user Johannes Schaub, solution to operator,() problem
The proper way of getting rid of the warnings is to not name the
parameters. If you still want to have their names visible, you can
simply comment them out:

int main(int /*argc, char** /*argv*/)

But the names have documentary value, and those comments do not nest,
e.g. for the purpose of commenting out code.

So include the names in the function declaration, but not in the definition.
 
J

Juha Nieminen

Alf P. Steinbach said:
<code>
#if !defined( CPP_DECLARE_UNUSED )
# define CPP_DECLARE_UNUSED( argName ) \
(void)(argName, void(), 0); struct argName; (void)0
#endif
// SO user sehe: "(void)0" for semicolon
// SO user R. Martinho Fernandes, pointed out operator void() problem
// SO user Johannes Schaub, solution to operator,() problem
</code>

That seems worse than just having the compiler warning.
 
Q

Qi

Qi said:
int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

This seemed like nonsensical code because it does nothing. Then I realized
that it's an ugly hack to silence the compiler warning about unused
variables. That's not how you do it.

Ugly? Maybe.
But it makes a lot of sense to me.

There is time that some parameters are not used. Such as implementing
an interface, and the interface function just has extra parameters for
flexibility.

Though I can write "int main(int, char **)", I won't do it because
I expect others may read my code and feel difficult to understand
the function without the parameter name.

For example,
int findSomeThing(int, int); // what's that? Don't know
int findSomeThing(int beginIndex, int endIndex); // oh, find between
// beginIndex, endIndex, but the function doesn't use them.

Of course we can put the parameter name to declaration and omit
in the definition, but then the reader needs to dig into the header
only for parameters when he is reading the source code.

int main(int /*argc*/, char** /*argv*/) ?
To me, it's more ugly and easier to misread than (void)argc.
**? */? How may * and / there in one line?

And I think "(void)argc" is well known for C++ developers, maybe
I'm wrong?
 
I

Ian Collins

Qi said:
int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

This seemed like nonsensical code because it does nothing. Then I realized
that it's an ugly hack to silence the compiler warning about unused
variables. That's not how you do it.

Ugly? Maybe.
But it makes a lot of sense to me.

There is time that some parameters are not used. Such as implementing
an interface, and the interface function just has extra parameters for
flexibility.

Though I can write "int main(int, char **)", I won't do it because
I expect others may read my code and feel difficult to understand
the function without the parameter name.

Then why don't you just write "int main()"?
For example,
int findSomeThing(int, int); // what's that? Don't know
int findSomeThing(int beginIndex, int endIndex); // oh, find between
// beginIndex, endIndex, but the function doesn't use them.

Of course we can put the parameter name to declaration and omit
in the definition, but then the reader needs to dig into the header
only for parameters when he is reading the source code.

If the parameter isn't used (and named), why would the reader look for it?
int main(int /*argc*/, char** /*argv*/) ?
To me, it's more ugly and easier to misread than (void)argc.
**? */? How may * and / there in one line?

And I think "(void)argc" is well known for C++ developers, maybe
I'm wrong?

Maybe, most people I know simply omit the name.
 
Q

Qi

Then why don't you just write "int main()"?

"main" function is only the one in my sample code.
I have a lot of functions that can't omit the parameters
completely...
If the parameter isn't used (and named), why would the reader look for it?

Because the parameter name can help readability and help to
understand the function, IMHO.
 
M

Miles Bader

Qi said:
And I think "(void)argc" is well known for C++ developers, maybe
I'm wrong?

I've never seen it used before.

OTOH, it's reasonably obvious what it does (to me at least)....

Whether it's more or less ugly than just commenting out the parameter
names, e.g. "int /*argc*/, char **/*argv*/" is a matter of opinion I
suppose...

-Miles
 
I

Ian Collins

"main" function is only the one in my sample code.
I have a lot of functions that can't omit the parameters
completely...


Because the parameter name can help readability and help to
understand the function, IMHO.

Surly the argument about how to comment out the name is evidence that
simply omitting the name is the best documentation for a parameter that
isn't used? I've yet to see a case where clutter helps readability.
 
M

Miles Bader

Ian Collins said:
Surly the argument about how to comment out the name is evidence that
simply omitting the name is the best documentation for a parameter
that isn't used? I've yet to see a case where clutter helps
readability.

I think it depends.

For instance, consider the initial (highest-level) definition of a
virtual method. You want the parameter names because they're acting
as documentation for the interface (and the method comment probably
refers to them by name). But I've found that I often use an inline
method body with a trivial "default definition" that doesn't reference
any of the parameters (and just returns false or something).

I don't want to use an out-of-line method definition for that method
(it's just annoying, and the inline definition actually provides good
documentation of such a trivial default), but the compiler complains
because I don't reference any of the arguments[*], although obviously
the arguments may be referenced by overrides. What I usually do is
just comment out parameter names.

[*] I actually submitted a bug report trying to make an argument that
g++ shouldn't warn about unreferenced arguments in inline definitions
of virtual methods, but didn't get much sympathy....

-miles
 
J

Juha Nieminen

Qi said:
Though I can write "int main(int, char **)", I won't do it because
I expect others may read my code and feel difficult to understand
the function without the parameter name.

So instead you put no-op lines of code that are even more confusing,
and which exist solely as a hack to get rid of some compiler warnings?
Of course we can put the parameter name to declaration and omit
in the definition, but then the reader needs to dig into the header
only for parameters when he is reading the source code.

Exactly how does knowing the parameter's name help understanding
the implementation of the function, which does not use said name?

"Hey, I can't understand this function implementation because one
of the unused parameters is not named. It confuses me. I have no idea
what this implementation, which doesn't use that parameter, is doing."
And I think "(void)argc" is well known for C++ developers, maybe
I'm wrong?

I have been programming with C++ for over 15 years, most of that
time professionally. I have never seen that hack used before.
 
Q

Qi

I have been programming with C++ for over 15 years, most of that
time professionally. I have never seen that hack used before.

Hmmm. Maybe I was wrong.
If "(void)argc" is not well known, I will definitely not use
it any longer.

Indeed when I first read "(void)argc" before I knew it, I needed
to think a moment about what it does...

Thanks for pointing that out.
 
Q

Qi

Hi all,

Thanks for let me know my that potential mistake.
I started another thread. Please post there for this topic.
It's too off topic in this thread. :)
 
J

Joe keane

int main(int argc, char * argv[])
{
(void)argc;
(void)argv;

string s;
test(s);

return 0;
}

That is an old C idiom, and there's nothing wrong with it.

Saying 'comment out the parameter' misses the point.
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top