Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Best practices for forward declaring a template function

2 views
Skip to first unread message

er

unread,
Nov 29, 2009, 3:11:47 PM11/29/09
to
Hello,

Let's begin with a library that defines:

// A_HPP
namespace library{
class A{};
A::value_type foo(const A& a){...}
}
// B_HPP
namespace library{
class B{};
B::value_type foo(const B& b){...}

}

and I want to extend it, but non intrusively i.e. outside of namespace
library. I proceed like this:

template<typename T> struct is_library : mpl::false_{}; and for each X
in {A,B},

// FWD_A_HPP
#include A_HPP
template<> struct is_library<X> : mpl::true_;

// FWD_FOO
namespace extension{

typename lazy_enable_if<is_library<X>,mpl::identity<typename
X::value_type> >::type
foo(const X& x){
return library::foo(x)
}

}

And I then define my own classes :
// C_HPP
namespace extension{
struct C{};
typename C::value_type foo(const C& c){...};
}


The limitation of the above, to use it say in main.cpp, is that I have
to

#include FWD_A_HPP

before

#include FWD_FOO

Correct?

If the number of dependencies is large, keeping track of which files
comes before other becomes tedious so I guess the standard solution is
to add a forwarding declaration inside FWD_FOO,

namespace library{
typename A::value_type foo(const A& a);
}

just before extension::foo. Correct?

The problem is further complicated by the fact that A, B and C, in my
actual problem, have template e.g.
template<typename T> struct A;
template<typename T,typename U> struct B;

but the function signature is always
templat<typename X>
typename X::value_type foo(const X&);

On some compilers (MSVC), the above does not work. I get a compile
error : ambiguous call to overloaded function.

What is the best practice for this kind of problem?


Alf P. Steinbach

unread,
Nov 29, 2009, 3:40:52 PM11/29/09
to
* er:

>
> Let's begin with a library that defines:
>
> // A_HPP
> namespace library{
> class A{};
> A::value_type foo(const A& a){...}
> }
> // B_HPP
> namespace library{
> class B{};
> B::value_type foo(const B& b){...}
>
> }

value_type is undefined.

Assuming you meant to define on in both class A and B.


> and I want to extend it, but non intrusively i.e. outside of namespace
> library. I proceed like this:
>
> template<typename T> struct is_library : mpl::false_{};
>
> and for each X in {A,B},
>
> // FWD_A_HPP
> #include A_HPP
> template<> struct is_library<X> : mpl::true_;
>
> // FWD_FOO
> namespace extension{
>
> typename lazy_enable_if<is_library<X>,mpl::identity<typename
> X::value_type> >::type
> foo(const X& x){
> return library::foo(x)
> }
>
> }

What's the point?


> And I then define my own classes :
> // C_HPP
> namespace extension{
> struct C{};
> typename C::value_type foo(const C& c){...};
> }

value_type is not defined.

There is no relation to the preceding explanation.


> The limitation of the above, to use it say in main.cpp, is that I have
> to
>
> #include FWD_A_HPP
>
> before
>
> #include FWD_FOO
>
> Correct?

No.


> If the number of dependencies is large, keeping track of which files
> comes before other becomes tedious so I guess the standard solution is
> to add a forwarding declaration inside FWD_FOO,
>
> namespace library{
> typename A::value_type foo(const A& a);
> }
>
> just before extension::foo. Correct?

Doesn't make sense so far.

> The problem is further complicated by the fact that A, B and C, in my
> actual problem, have template e.g.
> template<typename T> struct A;
> template<typename T,typename U> struct B;

So, now you're saying that all you've described so far has been *different* from
your problem.

> but the function signature is always
> templat<typename X>
> typename X::value_type foo(const X&);
>
> On some compilers (MSVC), the above does not work. I get a compile
> error : ambiguous call to overloaded function.

Error on line 42.


> What is the best practice for this kind of problem?

Check out the FAQ item on how to post a question about code that Does Not Work.


Cheers & hth.,

- Alf

er

unread,
Nov 29, 2009, 5:48:34 PM11/29/09
to
After reading the FAQ on code that does not work I'm starting from an
minimal example that I actually tested on XCode 3.2 (Mac OS X). But
before I get too carried away could Alf say if Koenif lookup is what
prompted this question

> What's the point?

Back to the example:

#ifndef HEADER1_HPP
#define HEADER1_HPP
namespace n1
{
struct A{ typedef double value_type; };
struct B{ typedef double value_type; };
A::value_type foo(const A& a){ return A::value_type(); }
B::value_type foo(const B& b){ return B::value_type(); }
}
#endif
#ifndef HEADER2_HPP
#define HEADER2_HPP
namespace n2
{
template<typename X>
typename X::value_type foo(const X& x){ return n1::foo(x); }
}
#endif

#include "header1.hpp"
#include "header2.hpp"
int main () {
n2::foo(n1::A());
return 0;
}

Build Succeeded. But changing the order of the include files
#include "header2.hpp"
#include "header1.hpp"
Causes the build to fail, which leads to my question : can / how to
modify the code so that in this order, the code compiles?


Alf P. Steinbach

unread,
Nov 29, 2009, 7:11:24 PM11/29/09
to
* er:

> After reading the FAQ on code that does not work I'm starting from an
> minimal example that I actually tested on XCode 3.2 (Mac OS X). But
> before I get too carried away could Alf say if Koenif lookup is what
> prompted this question
>
>> What's the point?
>

I just didn't see the point of all the mpl stuff and templates and so on.

Simply include [header1.hpp] from [header2.hpp].

That makes [header2.hpp] self contained.

You can optimize by introducing a [header1_fwd.hpp] (like e.g. [iosfwd]), but
there's probably no reason to.

If all the templated foo does is to forward a call then you may instead do

namespace n2 {
using n1::foo;

er

unread,
Nov 29, 2009, 7:47:10 PM11/29/09
to
>
> Simply include [header1.hpp] from [header2.hpp].
>
> That makes [header2.hpp] self contained.

Yes, but what if instead of header1.hpp I have header1_a.hpp and
header1_b.hpp, for A and B, respectively, and I want to selectively
include them (in actuality I would have many more than N = 2
classes)?

> You can optimize by introducing a [header1_fwd.hpp] (like e.g. [iosfwd]), but

Here's iosfwd (for my own understanding): Declares forward references
to several template classes used throughout iostreams.

> there's probably no reason to.

I guess you are suggesting to declare forward not just the classes but
their interface (foo). Right?

I was hoping to avoid this, because if M is the number of functions
(in my example M=1) for each class, I have MxN declarations.

>
> If all the templated foo does is to forward a call then you may instead do
>
>    namespace n2 {
>        using n1::foo;
>    }

I guess this makes the previous issues irrelevant, but for curiosity's
sake they still are.

>
> Cheers & hth.,
>
> - Alf

Yes it helps, thanks!

0 new messages