I wrote a parser class that contains base functionality for other, type specific parsers. For example, it contains a function to create an enum value from a string.
I didn't want the base class to contain information about the specific types, so I've implemented it as a template and used a trait to avoid including type specific headers:
// ParserBase.h
#include "EnumTrait.h"
template<typename EnumT>
EnumT parseEnum(std::string str)
{
return traits::EnumTrait<EnumT>::fromString(str);
}
The EnumTrait template is defined like so:
// EnumTrait.h
namespace traits
{
template<typename T>
struct EnumTrait
{
static_assert(sizeof(T) == -1, "Specialization not found");
};
} // namespace traits
Now, in each header where my enums are defined, there is also a specialization for this template. For example:
// Enum_A.h
#include "EnumTrait.h"
namespace A
{
enum class Enum_A
{
A
};
Enum_A fromString(std::string) {return Enum_A::A;}
} // namespace A
namespace traits
{
template<>
struct EnumTrait<A::Enum_A>
{
static std::string fromString(std::string str){ return A::fromString(str); }
};
// namespace traits
Headers for other enums look similar.
The usage of the base function:
// Enum_AParser.cpp
#include "ParserBase.h"
#include "Enum_A.h"
// ...
Enum_A foo = parseEnum<Enum_A>(bar);
// ...
My concern is: can this (does it) lead to ODR violations (or some other problems)?
It's impossible to use the trait with Enum_A and not have the specialization for it available, as they are defined in the same header.
But is it ok to not have every template specialization available in every TU where the template is used (for example Enum_A will not be available in the Enum_BParser)?
One thing I've noticed while thinking about this is that it is legal to create our own specializations of templates available in the standard library, so maybe it is ok after all?
I am using C++17, if that changes anything.
Looks OK to me. It is not required that every specialization be visible in every translation unit. It is only required that the specialization be declared before every use of the template that would otherwise trigger an implicit instantiation.
[temp.expl.spec]/7 If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required...
Related
I have a very simple CRTP skeleton structure that contains just one vector and a private accessor in the base class. There is a helper method in the CRTP class to access it.
#include <vector>
template<typename T>
class CRTPType {
// Will be used by other member functions. Note it's private,
// so declval/decltype expressions outside of friends or this class
// cannot see it
auto& _v() {
return static_cast<T *>(this)->getV();
}
};
class BaseType : public CRTPType<BaseType> {
friend class CRTPType<BaseType>;
std::vector<int> v;
//For different base types this impl will vary
auto& getV() { return v; }
};
So far so good. Now I want to add a using declaration to CRTPType that will be the type that _v() returns. So ideally, one could do something like the following:
template<typename T>
class CRTPType {
//Will be used by other member functions
auto& _v() {
return static_cast<T *>(this)->getV();
}
using vtype = decltype(std::declval<CRTPType<T>>()._v());
};
The problem is that the type is incomplete, so I cannot use any decltype/declval expressions within CRTPType.
Is there a clean way around this that breaks encapsulation as little as possible? Ideally in C++14, but I would be interested if there are any newer language features that help.
If you don't care so much where and how exactly the using declaration appears, then you can avoid the issue without much changes for example by putting the using declaration into a nested class:
template<typename T>
class CRTPType {
//Will be used by other member functions
auto& _v() {
return static_cast<T *>(this)->getV();
}
struct nested {
using vtype = decltype(std::declval<CRTPType<T>>()._v());
};
};
The issue in your original code is that using declarations are implicitly instantiated with the class template specialization and the point of implicit instantiation of CRTPType<BaseType> is before the definition of BaseType because the latter uses the former as a base class (which are required to be complete and are therefore implicitly instantiated).
Nested member classes are on the other hand specified not to be implicitly instantiated with the class template specialization and instead only when they are required to be complete. In other words the point of instantiation of the using declaration will now be immediately before the namespace scope declaration which actually, directly or indirectly, uses nested::vtype.
Another alternative is to make the using declaration a template:
template<typename T>
class CRTPType {
//Will be used by other member functions
auto& _v() {
return static_cast<T *>(this)->getV();
}
template<typename U = T>
using vtype = decltype(std::declval<CRTPType<U>>()._v());
};
Member templates can not be implicitly instantiated with the containing class template specialization either. It may be necessary to use the U = T construction and only use U in using = . The reason is that if the type on the right-hand side is not dependent on a template parameter, the compiler is allowed to check whether it can be instantiated immediately after the definition of the template, which is exactly what is not possible and we want to avoid. The program may therefore be ill-formed, no diagnostic required if only T is used. (I am really not 100% sure this applies here, but Clang does actually complain.)
Another possibility is to move the using declaration outside the class, in which case it is obvious that it will not be implicitly instantiated with it:
template<typename T>
class CRTPType;
template<typename T>
using CRTPType_vtype = decltype(std::declval<CRTPType<T>>()._v());
template<typename T>
class CRTPType {
//Will be used by other member functions
auto& _v() {
return static_cast<T *>(this)->getV();
}
};
Variations using nested classes or namespaces coupled with using declarations in the enclosing namespace can hide the additional name from the outside.
With all of the above you still need to be careful that nothing else in the instantiation of CRTPType<BaseType> or in the definition of BaseType actually indirectly uses vtype. If that happens you may be back to the original problem, potentially even depending on the declaration order of members (although that technically is not standard-conform behavior of the compilers).
In any case, you need to friend the CRTPType<BaseType> in BaseType or mark getV in BaseType as public.
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...
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.
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.
I've just been reading about template explicit instantiation:
template struct MyStruct<long>;
It was described as "quite rare", so under what circumstances would it be useful?
One of the use cases is to hide definitions from the end-user.
tpl.h:
template<typename T>
void func(); // Declaration
tpl.cpp:
template<typename T>
void func()
{
// Definition
}
template void func<int>(); // explicit instantiation for int
template void func<double>(); // explicit instantiation for double
main.cpp
#include "tpl.h"
int main()
{
func<double>(); // OK
func<int>(); // OK
// func<char>(); - Linking ERROR
}
Explicit instantiation is designed to optimize template libraries usage providing some of (mostly used) template instances in compiled binary form instead of source code form. This will reduce compile and link time for end-user applications. E.g. std::basic_string<char> and std::basic_string<wchar_t> can be explicitly instantiated in STL distribution avoid work on its instantiation in each translation unit.
Explicit instantiation is also useful when you want to encapsulate template implementation and you want this template to be used only with well-known set of types. In this case you can place only declarations of template functions (free or members) in header file (.h/.hpp) and define them in translation unit (.cpp).
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
// numeric_vector.cpp
//////////////////////////////////////////////////
// We know that it shall be used with doubles and ints only,
// so we explicitly instantiate it for doubles and ints
template class numeric_vector<int>;
template class numeric_vector<double>;
// Note that you could instantiate only specific
// members you need (functions and static data), not entire class:
template void numeric_vector<float>::sort();
template <typename T> void numeric_vector<T>::sort()
{
// Implementation
...
}
Also explicit instantiation can be useful when you need instantiated type from template but inside some syntax construction that doesn't trigger instantiation itself, e.g. some compiler-specific meta-feature like __declspec(uuid) in Visual Studio.
Note the difference with another technique that could be used for implementation encapsulation - explicit specialization. With explicit specialization you must provide specific definition for each type to be specialized. With explicit instantiation you have single template definition.
Consider the same example with explicit specialization:
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
template <> class numeric_vector<int>
{
...
void sort();
};
template <> class numeric_vector<double>
{
...
void sort();
};
// Specializing separate members is also allowed
template <> void numeric_vector<float>::sort();
// numeric_vector.cpp
//////////////////////////////////////////////////
void numeric_vector<int>::sort()
{
// Implementation for int
...
}
void numeric_vector<double>::sort()
{
// Implementation for double
...
}
void numeric_vector<float>::sort()
{
// Implementation for float
...
}
Having an explicit specialization allows you to hide the implementation, which, as you know, is usually impossible with templates.
I've seen this technique only once in a library that handled geometry, and they'd provide their own vector class.
So you could use
lib::Vector<MyShape>
with some basic functionality that lib::Vector provided, and basic implementations, and if you used it with their classes (some, not all)
lib::Vector<lib::Polygon>
you would use the explicit specialization. You wouldn't have access to the implementation, but I'm betting some hardcore optimizations were going on behind the scenes there.
If you really don't like defining template functions in header files, you can define the functions in a separate source file and use explicit template instantiation to instantiate all the versions you use. Then you only need a forward declarations in your header file instead of the complete definition.