I have a header which exposes a templated class and a typedef via using, something like:
namespace fancy {
struct Bar {
...
}
template<typename T>
class Foo {
...
}
using FooBar = Foo<Bar>;
}
I would like to forward declare FooBar to use it in a shared_ptr in another header. I've tried
namespace fancy {
using FooBar;
}
like for a class or struct, but without luck. Is this possible, and if so, how?
You can't declare a using alias without defining it. You can declare your class template without defining it, however, and use a duplicate using alias:
namespace fancy {
template <typename> class Foo;
class Bar;
using FooBar = Foo<Bar>;
}
Another way to use forward declare is to replace using with the class inheritance:
// using FooBar = Foo<Bar>;
class FooBar : public Foo<Bar> {};
Of course, now FooBar is not the same thing as Foo<Bar>. For instance, you need to inherit possibly existente constructors via using Foo<Bar>::Foo, but as a profit you can use easy forward declare as usual. Just:
namespace fancy {
class FooBar;
}
If your using declaration is too large (a lot of template parameters, which on their turn are also defined by a using statement), you could also add a dummy forward struct that has the using type as a dependent type:
namespace fancy {
struct Bar {
...
}
template<typename T>
class Foo {
...
}
using FooBar = Foo<Bar>;
// Forward struct
struct FooBarFwd {
using type = FooBar;
}
}
Then in your place where you want to forward declare:
namespace fancy {
class FooBarFwd;
}
// use your type as
typename FooBarFwd::type baz(const typename FooBarFwd::type & myFooBar);
// instead of
// FooBar baz(const FooBar & myFooBar);
Some disadvantages of this approach are
Using typename to disambiguate the dependent type.
Extra indirection for your type, some compilers could have problems when reporting errors.
Changing to this approach might need quite a lot of changes to your code (changing every occurence of FooBar with typename FooBarFw::type)
Therefore, I advise to apply this technique only when you are certain what you are doing.
Related
The Scenario:
Let's say we have several libraries, each in their own namespace, each containing the exact same set of classes and functions with the same API in every namespace. These libraries have absolutely no knowledge of one another and share no common bases.
namespace A {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
namespace B {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
namespace C {
class Foo { ... };
class Bar { ... };
class Baz { ... };
// A dozen more types
};
I am in no way defending this design, but let's take it as a constraint that can't be changed. There are clearly better ways of doing this, but I'm not at liberty to change that right now.
The Problem:
Given the above, we often want implement higher level code that makes use of these libraries, but we don't want to have to repeat this code for each one. Templates seem like the obvious solution.
template<typename Foo, typename Bar, typename Baz>
class FooBarBazzer
{
std::unique_ptr<Foo> foo;
std::vector<Bar> bars;
Baz baz;
...
}
This doesn't look too bad, but it requires us to list Foo, Bar and Baz as template parameters and as the number of types involved has grown, this has quickly lead to some seriously unwieldy template argument lists.
I find myself wanting the following imaginary syntax:
template<namespace ns>
class FooBarBazzer
{
std::unique_ptr<ns::Foo> foo;
std::vector<ns::Bar> bars;
ns::Baz baz;
...
}
One potential workaround is to write and maintain a trait struct for each namespace containing a member type for every type in that namespace.
namespace A {
struct Types {
using Foo = A::Foo;
using Bar = A::Bar;
using Baz = A::Baz;
// A dozen more type aliases
};
}
namespace B {
struct Types {
using Foo = B::Foo;
using Bar = B::Bar;
using Baz = B::Baz;
// A dozen more type aliases
};
}
namespace C {
struct Types {
using Foo = C::Foo;
using Bar = C::Bar;
using Baz = C::Baz;
// A dozen more type aliases
};
}
template<typename Types>
class FooBarBazzer
{
std::unique_ptr<typename Types::Foo> foo;
std::vector<typename Types::Bar> bars;
typename Types::Baz baz;
...
}
But that seems like a lot of boilerplate. (It's also a lot of typename keywords sprinkled around, which isn't ideal, but I doubt that's avoidable.)
The Question:
Is there some better trick to accomplish this? To tell a template at instantiation time which namespace it should be looking for types in? One that doesn't require writing and maintaining much boilerplate?
I suspect the answer is no, but I'm constantly amazed by the things that experts are able to make the C++ type system do.
Short Answer
There is no way to pass a namespace to a template; however that doesn't mean that there aren't alternatives to your situation.
Long Answer
Although there is no way to pass a namespace specifically to this, there is also no real reason why you can't support your use-case in a generic way. Your suggestion to use traits could definitely work -- but might be an unnecessary manual effort depending on the specifics of your problem.
You mention your concerns of growth for the number of types -- and this could be satisfied with a variadic argument list:
template<typename Foo, typename Bar, typename...Args>
bool DoAllFoosBar(const std::vector<Foo> & foos, const Bar & bar, const Args&...args)
{
return std::all_of(foos.begin(),
foos.end(),
[&](const auto & foo){ return IsFooBar(foo, bar, args...); });
}
As long as 1 of the arguments matches something unambiguously from the namespace (which from the sounds of it, it should), it will still call through ADL-qualification -- it just now supports two or more arguments.
Additionally, although you cannot constrain strictly on the namespace itself -- you can constrain the function to only be invocable if IsFooBar is invocable on its arguments -- either through SFINAE or just static_assert.
For example:
// Dummy definition in current scope, so it can find others through ADL
void IsFooBar();
template<typename Foo, typename Bar, typename...Args>
auto DoAllFoosBar(const std::vector<Foo> & foos, const Bar & bar, const Args&...args)
-> decltype(IsFooBar(foos, bar, args...))
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- expression sfinae
{
...
}
This uses Expression SFINAE to conditionally enable DoAllFoosBar if and only if IsFooBar(...) produces a valid result. Since it also sees IsFooBar in the current scope, it will look for all valid entries through ADL as well. You could also do something similar to turn this into a static_assert as well.
I am currently having trouble using namespaces with traits classes. Here is my tentative code structure:
namespace project {
namespace internal {
template<typename T> struct traits;
} // internal
namespace moduleA {
namespace internal {
class AImpl {
using some_typeA = traits<A>::some_type;
using some_typeAImpl = traits<AImpl>::some_type;
// where to put the traits specialization?? How the forward declaration could be done?
};
} // internal
class A {
A(): imp(new internal::AImpl()) {}
private:
internal::AImpl* imp;
};
} // moduleA
} // project
Here are my questions and I am looking for suggestions to make this code better follow the established conventions and best practices:
I am defining two internal namespaces, ::project::internal and ::project::moduleA::internal, is this a bad practice? My concern on this is that with two levels it might be easier for user to browse the documentation from doxygen, as all the moduleA related stuff, both moduleA::internal and not, are grouped together.
Because moduleA::internal::AImpl depends on the traits class of itself traits<AImpl>, and my traits templates resides in ::project::internal, so I have to either (1) define a traits template in moduleA::internal and specialize it; (2) define the traits specialization in ::project::internal. For this, I'll need forward-declare AImpl. How exactly should it be done for each of the case (1) or (2)? Does that mean I have to write code like this:
namespace project {
namespace moduleA {class A;}
namespace internal {
template<>
struct traits<module::A> {};
}
namespace moduleA {
... // more code
}
}
It looks like I am making too much use of namespace {} clauses.
Similar to 2, module::internal::AImpl depends on traits<A>, again I need to forward declare A, so the same problem.
I'd greatly appreciate you help on this, thank you!
Instead of using class templates for traits in C++11 you can use function declarations (no definition is necessary). Functions can be found using argument-dependent name lookup, so that you can specialise traits for your class in the same namespace where your class is declared.
This completely removes the nuisance of having to close the namespace of your class, open the traits namespace, specialise the trait for your class using its fully qualified name, close the traits namespace, re-open the namespace of your class. And also removes the need to include the declaration of the primary template.
Example:
#include <type_traits>
template<class T> struct Type {};
template<class T>
void trait_of(Type<T>); // Generic trait version.
namespace N {
struct A;
int trait_of(Type<A>); // Trait specialisation for A.
} // N
int main() {
using trait_of_a = decltype(trait_of(Type<N::A>{})); // trait_of is found using ADL.
static_assert(std::is_same<int, trait_of_a>::value, "");
}
The return type of the trait function can be a container of more types, e.g.:
template<class T>
void more_traits(Type<T>); // Generic trait version. Must be specialized.
namespace N {
struct MoreTraitsOfA {
using type_X = ...;
using type_Y = ...;
};
MoreTraitsOfA more_traits(Type<A>); // Trait specialisation for A.
} // N
using MoreTraits = decltype(more_traits(Type<N::A>{}));
using type_X = MoreTraits::type_X;
using type_Y = MoreTraits::type_Y;
I just finished an iteration on a library that I am writing.
In order to isolate certain types, I originally put them into a namespace.
Then, I realised that this namespace should actually be templated, so I turned it into a struct, ie:
namespace A
{
typedef _foo foo;
}
became
template <class T>
struct A
{
typedef _foo<T> foo;
};
This was more convenient to use in say, this situation:
template <class T>
class MyClass
{
public:
typedef A<T> nsA;
typedef typename nsA::foo foo_type;
};
Now, I'm using that library in another library, and there, I know that the template type T will never change. So I would like to do something like:
namespace B
{
using namespace A<double>;
}
but obviously, this doesn't work. Of course, I could just stop being lazy, and typedef manually each definition in A<double>, but I like being lazy when I can. Any thoughts on how to do something equivalent to this last step?
Actually, I just found the answer. Sorry, if you think this question was useless, I'll delete it, just let me know in comment.
Since I used a struct as a namespace in the first place, the solution is to keep using a struct as a namespace (!):
struct B
: public A<double>
{};
Here is a demo.
Let's say I got a class Test and a class TestImpl. I do not want to make the Impl be an inner class of Test. How can I at compile time create some global key-value (Type-Impl) repository where the type of Impl can be pulled using the Type?
Something like:
Impl<Test>::Type
This should result in TestImpl.
Define a generic template without an implementation, then specialize it:
template <typename T> struct Impl;
template<> struct Impl<Test> { typedef TestImpl Type; };
and so on, for each of the types you need.
One convenient way to organize interfaces and implementations is to use a tag that associates them:
template<typename TAG> class interface;
template<typename TAG> class impl;
template<typename> struct impl_of;
template<typename TAG>
struct impl_of<interface<TAG> > { using type = impl<TAG>; };
Then define the folowing:
namespace tag {
struct Test;
struct Foo;
struct Bar;
// etc.
}
using Test = interface<tag::Test>;
using Foo = interface<tag::Foo>;
using Bar = interface<tag::Bar>;
// etc.
Now your actual class definitions will not be Test, TestImpl etc., but rather specializations:
template<>
class interface<tag::Test> {
// Test class definition
};
template<>
class impl<tag::Test> {
// TestImpl class definition
};
The required mapping in this case is provided by impl_of, which is only defined once.
This may sound too much, but is powerful if you are going to define many classes (like interface, impl) and many traits (like impl_of) on them.
Given a template class like the following:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
How can someone forward declare this class in a header file?
This is how you would do it:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings;
template<typename Type, typename IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
Note that the default is in the forward declaration and not in the actual definition.
You can declare a templated class whose definition states the default arguments, but any time you reference the class you must include all its arguments until the definition is introduced.
eg. Let's use struct Foo without including it:
template <class>
struct Foo;
// Note that we *must* use the template here,
// even though in the definition it'll have a default.
template <class T>
auto Func (Foo<T> foo)
{
// do stuff with Foo before it's defined:
return foo.Bar();
}
int Func (int n)
{
return n;
}
We can then compile it without including the definition, eg.:
int main ()
{
return Func(3);
}
demo
...Or we can use it after including the definition, eg.:
template <class T = bool>
struct Foo
{
T Bar () {return 9;}
};
// Now the compiler understands how to handle
// Foo with no template arguments
// (making use of its default argument)
int main ()
{
return Func(Foo<>());
}
demo
I haven't checked the standards, but this works on clang/gcc with -std=c++98 up to -std=c++17, so if it's not officially a standard then it looks to be unofficially so.
Although in principal this should work for namespace std, and appears to in the examples I've checked (with many compilers), the standard states that it's undefined behaviour: According to the C++11 standard, 17.6.4.2.1:
The behavior of a C++ program is undefined if it adds declarations or
definitions to namespace std or to a namespace within namespace std
unless otherwise specified.
(I got this info from an SO answer).
Thanks to Antonio for pointing this out in the comments (and providing the link).
You can declare default arguments for a template only for the first declaration of the template. If you want allow users to forward declare a class template, you should provide a forwarding header. If you want to forward declare someone else's class template using defaults, you are out of luck!
My answer complements the others as the solution I found actually mitigates the need for a template class forward declaration by creating a new type when all parameters are known (or provided as default) so that this new type, than you can forward declare, is not a template anymore:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
You can then class Mappings;. I know that this solution doesn't apply everywhere but it did in my use case as I only used templates for high-performance dependency injection for non-virtual methods in a unit test context.