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?
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
> 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?
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;
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!