We have complex template classes that have some methods which will not work with certain policies or types. Therefore, when we detect those types (at compile time, using type-traits) we fire a static assertion with a nice message.
Now we do a lot of manual template instantiation as well. Partly it is so that the methods are forced to compiler to syntax check the methods. It also reduces compile time for the library user. The problem is that the static assertions are always fired and consequently we cannot manually instantiate the template class in question.
Is there a workaround for this?
EDIT: To make it clearer, here is an example (the explicit instantiation in this case will fail on someFunc1():
// header
template <typename T>
class someClass
{
void someFunc() {}
void someFunc1() { static_assert(false, assertion_failed); }
};
// source
template someClass<int>; // Explicit instantiation
EDIT2: Here is another example. This time you can compile it to see what I mean. First compile right away. The code should compile. Then Uncomment [2] and the static assertion should fire. Now comment out [2] and Uncomment [1]. The static assertion will fire because you are explicitly instantiating the template. I want to avoid removing explicit instantiation because of the benefits that come with it (see above for benefits).
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
//template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1();
foo<double> b;
//b.func1(); //[2]
return 0;
}
You can't have both: you can't have a static assertion to prevent instantiation and explicitly instantiate the type! This is an obvious contradiction. What you can have, however, is conditionally included functionality even though it is somewhat a pain in the neck: If a certain member function is not supposed to be supported for certain types, you can move this function into a base class which conditionally has it. This way you wouldn't use a static assertion but just remove the member function. I realize that this introduces interesting other problems, e.g. with respect to the location of member variables, but I think in the context you are describing this is the best you can get.
Here is a quick example of how this could look like:
template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base;
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ };
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } };
template <typename T>
struct Foo: foo_base<T> { /* .... */ };
template struct Foo<int>; // will have foo()
template struct Foo<double>; // will not have foo()
Alright, so if you're forcing the instantiation of all methods using explicit instantiation, you can't get away with any compile time tricks to prevent instantiation of the offending methods, such as enable_if. It'd be easy enough to move the error to runtime, but that's undesirable.
I think the best you can do is move the error to link time, which will statically ensure that the program does not contain a code path that could potentially call the prohibited function, but the error messages won't be very helpful to anyone that doesn't know about the restriction you're imposing. Anyway, the solution is to declare a specialization of the prohibited member functions but not define them:
template<typename T>
struct Foo {
void bar() {
std::cout << "bar\n";
}
void baz() {
std:: cout << "baz\n";
}
};
template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail
template struct Foo<int>;
template struct Foo<char>;
int main() {
Foo<int> f;
f.bar();
// f.baz(); // uncommenting this line results in an ugly link time error
Foo<char> b;
b.bar();
b.baz(); // works with Foo<char>
}
The static asserts no longer help give nice error messages when a mistake is made in client code, but you might want to leave them in because they'll fire if you forget to provide a specialization.
enable_if is a flexible mechanism for precise template methods targeting, may be what you are after. Example:
#include <string>
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
template <class T> class mywrapper
{
T _value;
template <class V>
typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_scalar<V>::value);
std::cout << "scalar: " << value << std::endl;
}
template <class V>
typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_compound<V>::value);
std::cout << "compound: " << value << std::endl;
}
public:
mywrapper(T const& value):_value(value) { }
void printval() { printval_(_value); }
};
template class mywrapper<int>;
template class mywrapper<std::string>;
int main()
{
mywrapper<int> ival(333);
mywrapper<std::string> sval("test");
ival.printval();
sval.printval();
return 0;
}
I did not get an opportunity to test enable_if as suggested by bobah but I did come up with a solution that does not require boost and that satisfies my original requirement to a good extent (I say good and not full, will explain at the end)
The solution is to put a dummy template on the code that will fail if compiled under some selected types and is fine under others. So:
struct dummyStruct {};
#define DUMMY_TEMP typename dummy
#define DUMMY_PARAM dummyStruct
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
template <typename T_Dummy>
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1<DUMMY_PARAM>();
foo<double> b;
//b.func1<DUMMY_PARAM>(); //[2] - this is a static error
return 0;
}
In all of my template code, these kind of functions (i.e. the ones that have static asserts OR work on some types and may fail on others by using type traits [in which case there is a selection of several different functions for different types]) are hidden from the client. So in my implementation, adding the extra dummy parameter is an OK compromise.
As a bonus, it lets me know that this function is designed to be used by only certain types. Furthermore, my original problem of explicit instantiation is solved by this simple technique.
Related
struct S
{
S(int);
S(std::string);
void foo(int);
void foo(std::string)
};
So my problem is that foo() should be invokable only with the type the ctor was. Solutions I can think of and problems with them:
Template the whole class. However this brings all the implementation details to the header, polluting it with many library #includes, making the API hard to read, making error messages long.
bool is_int runtime check. The assert() could be forgotten when implementing this API. The constraint is not evident from the API.
Separate classes. Violates DRY or forces all implementation to be extracted in .cpp-local functions - which is not so readable nor intuitive.
What other solutions are there? Or which of mine is the least silly?
Morally, your class is a template, but will only be instantiated with a type from a finite, known set of types. Your question is how to avoid some disadvantages of templates you identified: implementation details leaked, larger translation units, unintelligible API, and worse error messages.
The most straightforward way to implement this is to define and instantiate the templates out-of-line:
// S.h
#pragma once
#include <string>
#include <type_traits>
template<typename T>
struct S
{
static_assert(
std::is_same_v<T, int> ||
std::is_same_v<T, std::string>,
"S<T> only supports T=int or T=std::string"
);
S(T);
void foo(T);
};
extern template struct S<int>;
extern template struct S<std::string>
// S.cpp
#include "S.h"
#include <iostream>
template<typename T>
S<T>::S(T) { }
template<typename T>
void S<T>::foo(T t)
{
std::cout << "foo(" << t << ")\n";
}
template struct S<int>;
template struct S<std::string>;
// main.cpp
#include "S.h"
int main()
{
auto s = S{1};
s.foo(2); // prints "foo(2)\n"
}
Any translation units using S do not instantiate, and cannot instantiate, specializations of S. They rely on the instantiations provided. Implementation details are not exposed. Translation units are only as large as necessary to define the interface, not to implement it. The static assertion isn't required, but facilitates an early and obvious error.
As I got you have already implemented S. You can use the pimpl or S as a base class. Rename S to SImpl and make another templated S.
simpl.h
struct SImpl
{
SImpl(int);
SImpl(std::string);
void foo(int);
void foo(std::string)
};
s.h
#include "simpl.h"
template <typename T>
struct S: protected SImpl
{
S(T t) : SImpl(t) {}
void foo(T t) { SImpl::foo(t); }
};
I have observed that whenever a template class is specialized (partially/completely), all the member functions needs to be explicitly defined otherwise there is an error. Here is an example below
#include <iostream>
template<typename T, typename U> //Primary
struct test
{
void f() { std::cout << "\nPrimary"; }
void g() { std::cout << "Called g()\n";}
};
template <typename T> //Specialization
struct test<T, int*>
{
void f() { std::cout << "\nPartial Specialization"; }
};
template<> //Full specialization
struct test<int*, int*>
{
void f() { std::cout << "\nFull Specialization\n"; }
};
int main()
{
test<int, double> t1;
t1.f();
t1.g();
test<double, int*> t2;
t2.f();
t2.g();
test<int*, int*> t3;
t3.f();
t3.g();
}
Here t2.g() and t3.g() gives compile time error as they are not explicitly defined. If for every specialization, the member functions needs to be defined again. What's the advantage of allow partial/fully specialization?
I think you've got the concept of class specializations wrong here.
Class specialization is not inheritance. The specialized class is a different class than the initial one. Nothing is shared between the two. And hence, there doesn't exist any g() method in the specialized ones.
If you're looking for a way to just have the methods different, you should look into method specializations instead.
I think the main purpose for specialization is defining "exceptions" if you want to handle some data types in different ways.
Looking at partial specialization consider the following:
// NOT specialized
template <typename T>
struct test <T, T>
{
...
};
// partially specialized
template <typename T>
struct test <T*, T*>
{
...
};
The latter example is already partially specialized because you are telling the compiler to expect any type of pointer. And this can be useful of course because you might want to handle pointer-types slightly different to non-pointer types (checking for being NULL for example)
I recommend reading this article
Let's suppose to have a templateclass Foo:
template <typename T>
class Foo {
void foo();
};
I have another template class Bar (independent from the first one):
template <int N>
class Bar {};
Let's say, I want to specialise the foo() method for whatever Bar class.
I'd wrongly write:
template <>
template <int N>
void Foo<Bar<N> >::foo() { /* ... */ }
The compiler blames me for because the type is not complete:
error: invalid use of incomplete type 'class Foo<Bar<N> >'
void Foo<Bar<N> >::foo() { }
Code
I am using C++98, but I'd like to know if there exist different solutions in C++11.
Note
I could solve the problem specialising the entire class Foo for a generic Bar, but after I should have to define all methods.
Example Code
That's not what I want, I am looking for (if exists) more elegant solution (both C++98 and C++11) which allows me to specialise and implement only a single class method.
EDIT:
The question on SO does not explain how to specialise with a template argument. Indeed, my question shows how the compiler complains about that.
For C++11 you can SFINAE enable/disable (using std::enable_if) two differents versions of foo() inside a not specialized Foo class.
In C++98 you don't have std::enable_if but you can simulate it (give me some minutes and I try to propose an example). Sorry: my idea doesn't works because this method require the use of default template arguments for methods that is a C++11 innovation.
Another way is define a template base class for Foo(), say FooBase, insert foo() (and only foo()) in FooBase and specialize FooBase.
Another way, that works also with C++98, can be tag dispatching: you can define an unique foo(), with zero parameter, that call another foo(), with a parameter that is determined by T.
The following is a full (C++98 compilable) example
#include <iostream>
struct barWay {};
struct noBarWay {};
template <int>
struct Bar
{ };
template <typename>
struct selectType
{ typedef noBarWay type; };
template <int N>
struct selectType< Bar<N> >
{ typedef barWay type; };
template <typename T>
struct Foo
{
void foo (noBarWay const &)
{ std::cout << "not Bar version" << std::endl; }
void foo (barWay const &)
{ std::cout << "Bar version" << std::endl; }
void foo ()
{ foo(typename selectType<T>::type()); }
};
int main ()
{
Foo<int> fi;
Foo< Bar<42> > fb;
fi.foo();
fb.foo();
}
if a common base is not desirable, yet another way could be giving foo() a customization point, like a trait for example:
template <typename T>
struct foo_traits;
template <typename T>
struct Foo {
void foo(){ foo_traits<T>::foo_cp(*this); }
};
template <typename T>
struct foo_traits{ static void foo_cp(T&){/*default*/} };
template <int N>
class Bar {};
template <int N>
struct foo_traits<Bar<N>>{ static void foo_cp(Foo<Bar<N>>&){/*spec*/} };
such trait could also be an implementation detail friend, if its only purpose is to internally provide a foo() specialization for Bar's.
If you cannot specialize foo, define it so that it delegates the call to an internal foo-implementation class. Then specialize that class.
Something like this should compile in C++98 and it doesn't differ much from your original code:
template <typename T>
class Foo {
template<typename>
struct FooImpl;
public:
void foo() { FooImpl<T>()(); }
};
template <int N>
class Bar {};
template <typename T>
template <int N>
struct Foo<T>::FooImpl< Bar<N> > {
void operator()() { /* ... */ }
};
int main() {
Foo< Bar<0> > fb;
fb.foo();
Foo<int> fi;
//fi.foo();
}
The last line doesn't compile as expected (at least I got it was the expected result, just define the function call operator for FooImpl otherwise).
This way you can define selectively the specializations for which you want foo to work. In all the other cases, an attempt at using foo will result in a compilation error.
I'd like to know if there exist different solutions in C++11.
This is a classic use case for tagged dispatch, of which max66 already suggested. The approach, and even syntax, are basically the same in C++98 and C++11.
Here's a bit of a cleaner implementation than max66's, I believe (running on godbolt):
template <class T>
class Foo {
template <class>
struct tag{};
template<class U>
void foo_helper(tag<U>){std::cout << "default\n";}
void foo_helper(tag<Bar<3> >){std::cout << "specialization for Bar<3>\n";}
public:
void foo(){return foo_helper(tag<T>());}
};
The principle is the same; a client function accepting no arguments calls a helper function that constructs an empty type based on the T argument. Then normal overloading takes care of the rest.
Only here I use a templated catch-all method.
In C++11 the syntax would only change slightly; We could say tag<Bar<3>> instead of tag<Bar<3> > because new parsing rules allow the chevron for nested templates.
We could also make the tag and the templated foo_helper catch-all into variadic templates to be a little more generic:
template <class T>
class Foo {
template <class...>
struct tag{};
template<class... U>
void foo_helper(tag<U...>){std::cout << "default\n";}
void foo_helper(tag<Bar<3>>){std::cout << "specialization for Bar<3>\n";}
public:
void foo(){return foo_helper(tag<T>{});}
};
Things actually start getting pretty interesting in C++17 with the introduction of constexpr if that allows us to write what looks like normal branching logic based on T (Live Demo):
template <class T>
class Foo {
public:
void foo(){
if constexpr (std::is_same_v<T, Bar<3>>){std::cout << "Specialization for Bar<3>\n";}
else std::cout << "default\n";
}
};
As you can see, all the tag stuff goes away in favor of using a simple if statement.
We take advantage of type_traits introduced in C++11 to check the type of T against our desired type. Something like this wouldn't necessarily work previously because all branches needed to be compiled. In C++17, only the branch that is selected (at compile-time) is compiled.
Note that you could emulate this behavior as early as C++98 by using typeid (godbolt demo):
void foo(){
if (typeid(T) == typeid(Bar<3>)){std::cout << "Specialization for Bar<3>\n";}
else std::cout << "default\n";
}
However, the typeid approach is a poor choice for 2 reasons:
It's a run time check (slow) for information we know at compile-time
It's brittle because all branches must compile for all template instantiations, whereas in C++17 if constexpr only compiles the branch that is selected.
I am working on Visual Studio 2015 community edition
let's say I have, a simple class like this:
(The example below "should be" a compilable because it include all the necessary stuff, unfortunately, it produces an error).
#include <stdexcept>
template <typename T>
class class_foo
{
// members, methods, constructors. not important stuff...
// helper functions:
private:
class tag_aaa {}; // to resolve few things at compile-time, not run-time.
class tag_bbb {}; // - || -
template <typename tag>
void erase();
// for some reason this is not interpreted as an error by my compiler:
template<>
void erase<tag_aaa>();
template<>
void erase<tag_bbb>();
};
// catch-all-do-nothing "version"
// well, catch-all-throw-an-exception because call to this function is an obvious error.
// that should never occur.
template <typename T>
template <typename tag> inline
void class_foo<T>::erase()
{
throw std::runtime_error("Very weird error...");
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_aaa>()
{
// do some stuff...
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_bbb>()
{
// do some stuff...
}
int main()
{
class_foo<double> bar;
return 0;
}
The error:
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(36): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_aaa> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(43): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_bbb> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(51): warning : variable "bar" was declared but never referenced
I think about myself as a junior-hobbyist programmer, so certainly I am wrong, but I believe that both erase<class_foo<T>::tag_aaa>() and erase<class_foo<T>::tag_bbb>() are explicit specializations of the template <typename tag> void erase(); function. And as such, they are allowed. I believe that this error is due to some bad syntax but I can't find an error.
Question:
Is what I am trying to do, allowed?
If yes, what am I doing wrong?
If yes, what is the correct syntax for specializing this functions (erase)?
It look like full specialization of a template function but it's still partial specialization, hence the compilation error.
Why is it? Well, look at this specialization:
template <>
template <typename T>
inline void class_foo<T>::erase<class_foo<T>::tag_bbb>() {
// do some stuff...
}
You said it's a explicit specialization, but there is still a template parameter to fill! There's the parameter T yet to be known. So a specialization... that is still a template? That's a partial specialization!
Partial specialization of function is not allowed, for many reason. One of them is that it won't play nicely with overloading.
To effectively specialize the function, you must leave no template parameter to be known, something like this:
template<>
template<>
inline void class_foo<int>::erase<class_foo<int>::tag_bbb>() {
// do some stuff...
}
But it's not what you want.
Here's how I'd fix this problem. Use overloading instead of specializing:
template<typename T>
struct class_foo {
private:
struct tag_aaa {};
struct tag_bbb {};
void erase(tag_aaa) {
// Stuff when tag_aaa
}
void erase(tag_bbb) {
// Stuff when tag_bbb
}
};
Instead of invoking those like this:
erase<tag_aaa>(); // with specialization
You must invoke it like that:
erase(tag_aaa{}); // with overloading
If I have a template class specification like so,
template <typename T>
class MyClass {
public:
void fun1();
// ...
void funN();
};
template <typename T>
void MyClass<T>::fun1() {
// definition
}
// ...
template <typename T>
void MyClass<T>::funN() {
// definition
}
If I change the class template to something else, say I add an extra parameter:
template <typename T, typename U>
class MyClass {
// ...
};
Then I have to change each function definition (fun1, ..., funN) to agree with the class template specification:
template <typename T, typename U>
void MyClass<T,U>::fun1() { //... }
Are there any strategies for avoiding this? Could I use macros e.g.
#define DFLT_TEMPLATE template<typename T, typename U>
#define DFLT_CLASS class<T,U>
DFLT_TEMPLATE
void DFLT_CLASS::fun1() { // ... }
Or is this considered bad practice?
To me, the benefits of using a macro here are far overshadowed by the drawbacks. Yes, if you use a macro then if you ever need to add an additional template parameter, you'll only need to make a single modification. But anyone else reading your code is probably going to vomit.
I mean, are you going to do this for every template you have? Your code will become infested with ugly macros.
How many member functions do you have that this is an issue?
I think either they are small enough to be defined within the class template or the adaption of their algorithms to an additional template parameter would by far outweigh the replacement of those function headers.
Also, your editor ought to do this for you in no time anyway.
yes you could but don't forget to use "#undef DFLT_TEMPLATE" and "#undef DFLT_CLASS" at the end of file to avoid compiler warnings if your project have several templates with same macros definitions
Inheritation is better than macro.
If you want to change only a few functions and variables, make the specialized class inherit a common class that provides common functions/variables.
As far as possible, put the function definitions in the class template definition. It's a template, so unless you're using Comeau compiler, it's not as if they're going to be off in a different TU.
If the functions use something which is defined in between the class definition and the function definition, then you can play tricks to make that thing dependent on a template parameter even when "really" it isn't. For example:
template <typename T>
struct Foo {
void usebar();
};
struct Bar {
int a;
Foo<int> circularity; // circular dependency between Foo and Bar
Bar() : a(3) {}
};
template <typename T> void Foo<T>::usebar() {
Bar b;
std::cout << b.a << "\n";
}
Becomes:
// we only have to write "same" once
template <typename T, typename U>
struct same {
typedef U type;
};
struct Bar;
template <typename T>
struct Foo {
void usebar() {
typename same<T,Bar>::type b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity; // circularity gone
Bar() : a(3) {}
};
Or actually in this case just:
struct Bar;
template <typename T, typename B = Bar>
struct Foo {
void usebar() {
B b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity;
Bar() : a(3) {}
};
All cases support the following code:
int main() {
Foo<int> f;
f.usebar();
}
I would consider this approach bad practice. What you are complaining about is that you have changed your design (you need an extra template parameter) and now want a kludge to save on typing?
Introducing macros is going to decrease the readability of your code. Preprocessor definitions certainly have their place, but personally I'd never advocate one on the grounds that I can't be bothered to change my functions.
There are probably some (more or less bad) workarounds, but you definitely point out a " missing" feature of C++: class namespace extension.
Some people already proposed to extend C++ in this way:
http://www.lrde.epita.fr/dload//20080709-Seminar/ordy-classnamespaces.pdf
namespace foo
{
class bar
{
typedef int baz_t;
baz_t my_method ();
};
}
namespace class foo::bar
{
baz_t my_method ()
{
// ...
}
}
--
Using a macro is not a good idea (usual things about macros ....).
I would prefer, at worst, write function members definitions inline in this case, or even better use an editor than can help you easily update your class definition.
Macros are bad because they let you write code editing functions where you are supposed to write programs.
If you want to edit code, use your editor (sed, M-x replace-*, Find&Replace ...)