traits class, namespace and forward declaration - c++

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;

Related

Can you use a namespace while adding to it? Or is that confusing?

So I've got a library with many files and each one I want to add to the namespace of my library. In my declaration of a class I currently have:
namespace Vira {
template <typename GeometryT, typename AlbedoT>
class Camera : public Vira::RigidBody<GeometryT> {...};
};
This is fine but it feels as if the inside of the declaration gets messy with how many times I need to append Vira:: before using things. Would it instead be a good idea to use:
using namespace Vira;
namespace Vira {
template <typename GeometryT, typename LightT>
class Camera : public RigidBody<GeometryT> {...};
};
Or is this unclear/confusing/bad practice?
This is my first experience working with namespaces. The closest experience I have is from python where its common practice to import AnnoyinglyLongName as aln or something similar. Which I understand is useful in C++ as well in certain circumstances. For example, I use the following quite often:
template <typename GeometryT>
using Vec3 = Vira::Vector3<GeometryT>;
But I'm unsure if its a good idea to broadly use a namespace while I'm adding something to that namespace.
Code inside of a namespace doesn't need to explicitly qualify members of the same namespace. So, in this code:
namespace Vira {
template <typename GeometryT, typename AlbedoT>
class Camera : public Vira::RigidBody<GeometryT> {...};
};
The Vira:: qualification is redundant and can be removed:
namespace Vira {
template <typename GeometryT, typename AlbedoT>
class Camera : public RigidBody<GeometryT> {...};
};

SFINAE-based Operator Overloading across Namespaces

I'm attempting to use an approach which allows for automatic enabling of bitmask operators for strongly typed enum classes. See below header and cpp of an example.
https://www.justsoftwaresolutions.co.uk/files/bitmask_operators.hpp
https://www.justsoftwaresolutions.co.uk/files/testbitmask.cpp
The approach in testbitmask.cpp works when everything is in the same namespace, however I would like to separate the SFINAE code in a different namespace from the usage by other classes (see below or https://wandbox.org/permlink/05xXaViZT3MVyiBl).
#include <type_traits>
namespace ONE {
template<typename E>
struct enable_bitmask_operators{
static const bool enable=false;
};
template<typename E>
inline typename std::enable_if<enable_bitmask_operators<E>::enable,E>::type
operator|(E lhs,E rhs){
typedef typename std::underlying_type<E>::type underlying;
return static_cast<E>(
static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
}
}
namespace TWO {
enum class A{ x=1, y=2};
}
namespace ONE {
template<>
struct enable_bitmask_operators<TWO::A>{
static const bool enable=true;
};
}
int main(){
TWO::A a1 = TWO::A::x | TWO::A::y;
}
This has the effect of not being able to find the overloaded operator in main. Explicitly calling the function works (TWO::A a1 = ONE::operator|(TWO::A::x , TWO::A::y);), but of course is not the desired functionality.
If we move the specialization into namespace ONE, the compiler throws an error: declaration of 'struct ONE::enable_bitmask_operators<TWO::A>' in namespace 'TWO' which does not enclose 'ONE'. I'm wondering if the desired approach is possible in C++?
Your function cannot be found by ADL, you might add some using to allow to use it:
using ONE::operator|;
TWO::A a1 = TWO::A::x | TWO::A::y;
Demo
using namespace ONE; might be an alternative too.

Simulating argument-dependent lookup for template arguments

I've encountered this problem while writing some library-like code recently, and I thought discussing it might help others as well.
Suppose I have a library with some function templates defined in a namespace. The function templates work on types supplied by client code, and their inner workings can be customized based on type traits defined for the client types. All client definitions are in other namespaces.
For the simplest example possible, a library function would basically have to look like this (note that all the code snippets are just wishful thinking, nothing compiles):
namespace lib
{
template<typename T> void f()
{
std::cout << traits_for<T>::str() << '\n'; //Use the traits in some way.
}
}
Client code would look like this:
namespace client
{
struct A { };
template<> std::string traits_for<A>::str() { return "trait value"; }
}
And then someone, somewhere could call
lib::f<client::A>();
and everything would magically work (the specialization of lib::f() would find the traits explicit specialization in the namespace where the template argument for T is declared, just like ADL does for functions and their arguments). The goal is to make it as easy as possible for client code to define those traits (there could be several) for each client class (there could be lots of those).
Let's see what we could do to make this work. The obvious thing is to define a traits class primary template in lib, and then explicitly specialize it for client types. But then clients can't define those explicit specializations in their own namespace; they have to exit it, at least up to the global namespace, define the explicit specialization, then re-enter the client namespace, which, for maximum fun, could be nested. I'd like to keep the trait definitions close to each client class definition, so this namespace juggling would have to be done near each class definition. Suddenly, a one-liner in client code has turned into a messy several-liner; not good.
To allow the traits to be defined in the client namespace, we could turn the traits class into a traits function, that could be called from lib like this:
traits_for(T())
but now we're creating an object of class T just to make ADL kick in. Such objects could be expensive to construct (or even impossible in some circumstances), so this isn't good either. We have to keep working with types only, not their instances.
Giving up and defining the traits as members of the client classes is not an option either.
Some plumbing required to make this work would be acceptable, as long as it doesn't complicate the definitions for each class and trait in the client namespace (write some code once, but not for every definition).
I've found a solution that satisfies these stringent requirements, and I'll write it up in an answer, but I'd like to find out what people think about this: alternatives, critique of my solution, comments about how all of this is either bleeding obvious or completely useless in practice, the works...
To find a declaration based on some argument, ADL looks like the most promising direction. So, we'll have to use something like
template<typename T> ??? traits_helper(T);
But we can't create objects of type T, so this function should only appear as an unevaluated operand; decltype springs to mind. Ideally, we shouldn't even assume anything about T's constructors, so std::declval could also be useful:
decltype(traits_helper(std::declval<T>()))
What could this do? Well, it could return the actual traits type if the helper would be declared like this:
template<typename T> traits_for<T> traits_helper(T);
We've just found a class template specialization in another namespace, based on the declaration of its argument.
EDIT: Based on a comment from Yakk, traits_helper() should take a T&&, to allow it to work if T's move constructor is not available (the function may not actually be called, but the semantic constraints required for calling it must be met). This is reflected in the complete sample below.
All put together in a standalone example, it looks like this:
#include <iostream>
#include <string>
#include <utility>
namespace lib
{
//Make the syntax nicer for library code.
template<typename T> using traits_for = decltype(traits_helper(std::declval<T>()));
template<typename T> void f()
{
std::cout << traits_for<T>::str() << '\n';
}
}
namespace client_1
{
//The following two lines are needed only once in every client namespace.
template<typename> struct traits_for { static std::string str(); };
template<typename T> traits_for<T> traits_helper(T&&); //No definition needed.
struct A { };
template<> std::string traits_for<A>::str() { return "trait value for client_1::A"; }
struct B { };
template<> std::string traits_for<B>::str() { return "trait value for client_1::B"; }
}
namespace client_2
{
//The following two lines are needed only once in every client namespace.
template<typename> struct traits_for { static std::string str(); };
template<typename T> traits_for<T> traits_helper(T&&); //No definition needed.
struct A { };
template<> std::string traits_for<A>::str() { return "trait value for client_2::A"; }
}
int main()
{
lib::f<client_1::A>(); //Prints 'trait value for client_1::A'.
lib::f<client_1::B>(); //Prints 'trait value for client_1::B'.
lib::f<client_2::A>(); //Prints 'trait value for client_2::A'.
}
Note that no objects of type T or traits_for<T> are created; the traits_helper specialization is never called - only its declaration is used.
What's wrong with just requiring clients to throw their specializations in the right namespace? If they want to use their own, they can:
namespace client
{
struct A { };
struct traits_for_A {
static std::string str() { return "trait value"; }
};
}
namespace lib
{
template <>
struct traits_for<client::A>
: client::traits_for_A
{ };
}
Could even give your users a macro if you don't want them to write all that out:
#define PROVIDE_TRAITS_FOR(cls, traits) \
namespace lib { \
template <> struct traits_for<cls> : traits { }; \
}
So the above can become
PROVIDE_TRAITS_FOR(client::A, client::traits_for_A)
ADL is awesome. Keep it simple:
namespace lib {
// helpers for client code:
template<class T>
struct default_traits{
using some_type=void;
};
struct no_traits{};
namespace details {
template<class T,class=void>
struct traits:lib::no_traits{};
template<class T>
struct traits<T,decltype(void(
traits_func((T*)0)
))>:decltype(
traits_func((T*)0)
){};
}
template<class T>
struct traits:details::traits<T>{};
}
Now simply add in the type Foo namespace:
namespace bob{
// use custom traits impl:
struct foo{};
struct foo_traits{
using some_type=int;
};
foo_traits traits_func(foo const*);
// use default traits impl:
struct bar {};
lib::default_traits<bar> traits_func(bar const*);
// use SFINAE test for any type `T`:
struct baz {};
template<class T>
std::enable_if_t<
std::is_base_of<T,baz>{},
lib::default_traits<T>
>
traits_func(T const*)
}
and we are done. Defining traits_func that takes a pointer convertable from foo* is enough to inject the trait.
If you fail to write such an overload, we get an empty traits, which is SFINAE friendly.
You can return lib::no_traits in an overload to explicitly turn off support, or just don;t write an overload that matches a type.

C++ Forward declare using directive

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.

How to access hidden template in unnamed namespace?

Here is a tricky situation, and i wonder what ways there are to solve it
namespace {
template <class T>
struct Template { /* ... */ };
}
typedef Template<int> Template;
Sadly, the Template typedef interferes with the Template template in the unnamed namespace. When you try to do Template<float> in the global scope, the compiler raises an ambiguity error between the template name and the typedef name.
You don't have control over either the template name or the typedef-name. Now I want to know whether it is possible to:
Create an object of the typedefed type Template (i.e Template<int>) in the global namespace.
Create an object of the type Template<float> in the global namespace.
You are not allowed to add anything to the unnamed namespace. Everything should be done in the global namespace.
This is out of curiosity because i was wondering what tricks there are for solving such an ambiguity. It's not a practical problem i hit during daily programming.
I know it somewhat spoils your point, but I really think the main trick is to avoid something like this like the plague.
Using C++0x:
namespace {
template<class T> struct Template { };
}
typedef Template<int> Template;
#include<iostream>
template<typename T>
void PrintType() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template<typename FullType, typename NewParameter>
class Rebind {
template<template<class> class Template, typename OldParameter>
static Template<NewParameter> function(Template<OldParameter>);
public:
typedef decltype(function(FullType())) NewType;
};
int main()
{
PrintType< ::Template>();
PrintType<Rebind< ::Template, float>::NewType>();
return 0;
}
With gcc45 that yields
void PrintType() [with T = <unnamed>::Template<int>]
void PrintType() [with T = <unnamed>::Template<float>]
Apparently it compiles with Cormeau, but I only have access to their online test, so I'm stuck just assuming it functions as expected.
I couldn't figure out any way to pass an actual type to a struct directly and have it degrade into a template type, but the compiler had no problems stripping the two when it had to guess at function parameters. Maybe this works in C++03 using boost::result_of instead of decltype, but I've never used it before so I figured I'd stick to what I know.
Note the spacing within main. Rebind<::Template, float>::NewType gets gobbled by the parser because of <: being a digraph. I think it gets turned into Rebind[:Template, float>::NewType. So the space before ::Template is vital.
As an aside, I had no idea nested template parameters couldn't use typename [template<template<typename> class T> rather than template<template<typename> typename T>]. I think I relearn that every time I try to remember the syntax for the construct.
It's possible to access the global typedefed template by being explicit about the namespace, ie
::Template a
is a Template<int> from the anonymous namespace. Not sure if you can get a Template<float>.
Surprisingly Clang's C++ compiler is fine with the following, probably not standard behaviour:
#include <iostream>
namespace {
template <class T>
struct Template {T value;};}
typedef Template<int> Template;
int main(){
::Template a;
Template<float> b;
a.value = 6;
b.value = 3.14;
std::cout<<a.value<<" "<<b.value<<"\n";
}
disclaimer: I don't know why you'd want to do this and would probably speak sternly to someone who did.
namespace
{
template <typename T> class Template { };
}
typedef Template<int> IntTemplate;
typedef Template<float> FloatTemplate;
typedef IntTemplate Template;
int main() {
::Template t;
FloatTemplate ft;
}