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.
Related
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've spent some time trying to realize why my code doesn't compile and I've realized that in C++ Argument Dependent Lookup uses template typename arguments to determine name lookup scope.
#include <string>
#include <functional>
namespace myns {
template<typename T>
struct X
{};
template<typename T>
auto ref(T) -> void
{}
} // namespace myns
auto main() -> int
{
ref(myns::X<int>{});
ref(myns::X<std::string>{}); // error: call to 'ref' is ambiguous
}
So the former ref call compiles, because for myns::X<int> only myns::ref is considered, while the latter doesn't compile because it finds myns::ref() as well as std::ref
My question is how this can be useful? Why would I need this? Do you have any ideas, examples? For now I can only see drawbacks like in the example above, where it introduces unneeded ambiguity.
Suppose you put all the things into your own namespace, including a user-defined class, and a function which takes std::vector as the parameter. i.e.
namespace myns {
struct X {};
template<typename T>
auto my_func(const std::vector<T>&) -> void
{}
} // namespace myns
then you can take advantage of the fact that ADL also considers the types provided as template arguments and just write:
my_func(std::vector<myns::X>{});
on the other hand:
my_func(std::vector<int>{}); // error, can't find my_func
myns::my_func(std::vector<int>{}); // fine
Get back to your original question, the lesson here is don't use names from standard libraries, it just makes codes confusing.
In one word: reuse. It allows you to use useful components from other libraries, and still have ADL applied.
For instance:
namespace my_stuff {
class my_class {
// Something useful here
};
void process(std::unique_ptr<my_class> item);
}
Now you can write code naturally, as you would when working with the class directly:
process(std::make_unique<my_class>());
If it wasn't the case, you'd need to roll out your own smart pointer, in your own namespace, just to facilitate good coding idioms and ADL.
I am writing a library and there is a function that performs an (unqualified) call to free function foo using an arbitrary type as argument:
namespace lib {
template <typename T>
auto libfunc(T && t)
{
return foo(std::forward<T>(t));
}
} // namespace lib
A user of the library can write an overload of foo for his own types:
namespace app {
class Foo { };
template <typename> class Bar { };
int foo(Foo const &) { return 99; }
template <typename T>
char foo(Bar<T> const &) { return 'x'; }
} // namespace app
The correct funtion foo is found by ADL so code like this works:
app::Foo foo;
app::Bar<void**> bar;
auto x = lib::libfunc(foo);
auto y = lib::libfunc(bar);
However, if I want to write a version of foo that works for types from the std-namespace, no matching function foo is found unless I place foo in the std-namespace which is not allowed:
#ifdef EVIL
namespace std {
#endif
template <typename T>
double foo(std::vector<T> const & ) { return 1.23; }
#ifdef EVIL
} // namespace std
#endif
std::vector<int> vec;
lib::libfunc(vec); // Only works if EVIL is defined
Is it possible to change the code so that a user can enable the functionality foo for a type without invading its namespace? I thought about partial template specializations of a class template in the lib-namespace but is there any other possibility?
I've found two solutions to this problem. Both have their downsides.
Declare All Std Overloads
Let overloads for standard types be found by normal lookup. This basically means declaring all of them before using the extension function. Remember: when you perform an unqualified call in a function template, normal lookup happens at the point of definition, while ADL happens at the point of instantiation. This means that normal lookup only finds overloads visible from where the template is written, whereas ADL finds stuff defined later on.
The upside of this approach is that nothing changes for the user when writing his own functions.
The downside is that you have to include the header of every standard type you want to provide an overload for, and provide that overload, in the header that just wants to define the extension point. This can mean a very heavy dependency.
Add Another Argument
The other option is to pass a second argument to the function. Here's how this works:
namespace your_stuff {
namespace adl {
struct tag {}
void extension_point() = delete; // this is just a dummy
}
template <typename T>
void use_extension_point(const T& t) {
using adl::extension_point;
extension_point(t, adl::tag{}); // this is the ADL call
}
template <typename T>
void needs_extension_point(const T& t) {
your_stuff::use_extension_point(t); // suppress ADL
}
}
Now you can, at basically any point in the program, provide overloads for std (or even global or built-in) types like this:
namespace your_stuff { namespace adl {
void extension_point(const std::string& s, tag) {
// do stuff here
}
void extension_point(int i, tag) {
// do stuff here
}
}}
The user can, for his own types, write overloads like this:
namespace user_stuff {
void extension_point(const user_type& u, your_stuff::adl::tag) {
// do stuff here
}
}
Upside: Works.
Downside: the user must add the your_stuff::adl::tag argument to his overloads. This will be probably seen as annoying boilerplate by many, and more importantly, can lead to the big puzzling "why doesn't it find my overload" problem when the user forgets to add the argument. On the other hand, the argument also clearly identifies the overloads as fulfilling a contract (being an extension point), which could be important when the next programmer comes along and renames the function to extensionPoint (to conform with naming conventions) and then freaks out when things don't compile anymore.
The compiler doesn't complain when I do this ;-)
// Myfile.h
#include <iostream>
#include <vector>
namespace std
{
template<> class vector<int>
{
public:
vector ()
{
std::cout << "Happy Halloween !!!\n";
}
};
}
Is there any way to prevent this kind of undesirable specialization of a class/function template?
--EDIT--
I just used std:: as an example. What I'm looking for is a way to prevent this from happening to any template class.
What you do is specialize a standard library type inside a standard namespace.
Except for a few documented customization points (std::swap, std::hash<>) or specificly constrained specializations for User Defined Types (e.g. MySmartPtr<T>) this is against the specification and the result is undefined behaviour.
Edit: There is no mandatory diagnostic for this kind of rule violation.
To make it marginally harder for clients of your library to mess things up, you can do this trick:
namespace Public {
namespace Hidden { // DON'T TOUCH THESE!
template <typename> struct MyType { };
}
using Hidden::MyType;
}
Now, attempting to specialize MyType<> in namespace Hidden will fail.
No, the C++ language does not provide a general mechanism by which you can say "don't allow specializations of this template".
But it may not matter. For any instantiation that your code uses already, a user provided specialization will violate the one definition rule and their program may blow up in a fireball.
If you aren't using the instantiation in your library then what they do doesn't matter.
This is one of the cases where in C++ you simply can't prevent your user from shooting themself in the foot and if they choose to do so the responsibility is on them.
An alias template can not be specialized and has the behaviour you need for class templates.
template<class T>
struct my_class_implementation_which_should_not_be_used_directly
{
// impl
};
template<class T>
using my_class = my_class_implementation_which_should_not_be_used_directly<T>;
In addition you should document that specialising my_class_implementation_which_should_not_be_used_directly results in undefined behavior. Now your libraries user can not specialize my_class accidentally and is warned about the class with the ugly name directly.
Edit:
You can prevent specializations of your templates with enable_if in C++11. This is impractical though.
#include <type_traits>
template<
typename real_t,
typename = typename std::enable_if<
std::is_floating_point<real_t>::value
>::type
>
struct check_t;
template<
typename real_t,
typename = typename
std::enable_if<
std::is_floating_point<real_t>::value,
check_t<real_t>
>::type
>
class vec_t
{
};
#if 1
template<>
class vec_t<int> {};
template<>
class vec_t<int,check_t<int>> {};
#endif
void test()
{
vec_t<float> vecf;
vec_t<int> veci;
}
link
main.cpp:26:16: error: no type named 'type' in 'struct std::enable_if<false, void>'
The best way to prevent such behavior is through coding standards and code review.
You cannot force the compiler into an error in this case (other than using workarounds like those suggested in other answers), because that behavior is actually allowed by the language, although it's real usefulness can be questioned.
The matter is - it is very possible that you want/need to provide a generic behavior for multiple types (hence the use of templates) but you need to provide a specific implementation for some of the allowed types (notably std::string)
A quick & dirty example (it's a function, but the same could apply to classes) could be the following:
template<typename TData> TData GetData(std::string argument)
{
std::stringstream stream;
TData retVal;
stream.str(argument);
stream >> retVal;
return retVal;
}
However this is going to fail with std::string, as the >> operator would stop after the first blank space. So you could provide a dedicated specialization.
template<> std::string GetData(std::string argument)
{
return argument;
}
There are a few ways to go about this. You can declare specific specializations without defining them. eg:
template<> struct MyStruct<int>;
That way, if someone tries to instantiate with an int, they would get this specialization and it won't compile because there is n definition. Then you can write a simple macro to do this for all the types you don't want a specialization for.
For the inverse of this, make the definition empty:
template<typename T> struct MyStruct{};
Then define the specific types you plan to support:
template<> struct MyStruct<int> {...};
template<> struct MyStruct<std::string> {...};
//etc...
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;
}