Optional code in a template class - c++

Assume that we have that struct X; and we use C++11 compiler (e.g. gcc 4.7). I'd like to emit some code and attributes if and only if, say, opt = true.
template <bool opt>
struct X {
void foo() {
EMIT_CODE_IF(opt) {
// optional code
}
// ...common code...
}
int optional_variable; // Emitted if and only if opt is true
};
As for the code, I assume that normal if suffices.
But as for the attributes, if one leaves them unused (when opt = false), will and COULD they be automatically omitted by the compiler? I definitely do not want them there when opt = false.

The approach to avoid attributes in a class template is to derive from a base class template which is specialized to be empty if the member shouldn't be there. For example:
template <bool Present, typename T>
struct attribute {
attribute(T const& init): attribute_(init) {}
T attribute_;
};
template <typename T>
struct attribute<false, T> {
};
template <bool opt>
class X: attribute<opt, int> {
...
};
With respect to optional code you may get away with a conditional statement but often the code wouldn't compile. In this case, you'd factor out the code into a suitable function object which be specialized to do nothing when not needed.

Related

How can I force the user of a library template to explicitly tag particular template parameters as acceptable (but only sometimes)?

I have a family of classes in a library that can be "installed" in another class, either as a single member or as an array, dependent on the application. The arrays are indexed with an integer or enum type, dependent on the application (void is used when an array is not meaningful). The installable class itself has no control over the indexing; the application using the class defines the index.
However, I imagine that unwanted specialziations could be created by a typo and compile OK.
I want to constrain the indexing types to only the ones intended for the application, by making the client signal back to the library which associations are OK. I couldn't see a pure template metaprogramming approach, so I thought I'd exploit ODR and explicit specialization of class members.
namespace foo {
template <class P, class ROLE>
struct association
{
static_assert(std::is_enum_v<ROLE>||std::is_integral_v<ROLE>);
static const bool allowed();
};
template <class T>
class bar final
{
public:
bar() = default;
~bar() = default;
};
void do_something() {}
template <class I, class ROLE>
void install(I &&i, ROLE r)
{
if (association<std::decay_t<I>, ROLE>::allowed()) do_something();
}
template <class I>
void install(I &&i)
{
if (association<std::decay_t<I>, void>::allowed()) do_something();
}
}
With the following sample use:
// declare the indexing type
enum myindex { min=0, max=3 };
int main() {
foo::bar<int> foobar;
foo::install(foobar, myindex::min);
return 0;
}
There should be a linker error unless we also add
// add a definiton to make the association with myindex OK
template <> const bool foo::association<bar<int>, myindex>::allowed() { return true; }
In the full code, the value of "allowed" doesn't matter, only the existence of a definition does.
It's a pretty cryptic way of saying "this association is OK", but it works. At least, if you fully specialize association. But this is where the "sometimes" comes in: Some of the templates are supposed to work with any indexing type. It's a pain to make the library user write out specializations for these templates. But the following
template <class T, class ROLE> const bool foo::association<foo::bar<T>, ROLE>::allowed () { return true; }
is a compiler error, because it's not a full specialization.
Is there a way to fully define association::allowed() for all combinations of bar specializations with any ROLE, but force the user to define it for other templates?
If not, is there a better approach that accomplishes this goal? (Hopefull, something that can be used with static_assert because what I have now is charitably called 'clunky').
Remember, myindex cannot be rolled into the library. (I'm sticking to C++17 for the time being).
This case seems like a good place for template variables. One of their use is to make them a kind of a map - which in this case would greatly increase readability of the client code and move everything to compile-time. If you just want to break compilation the following should be fine:
#include <iostream>
#include <type_traits>
// make_association is a variable template which works as a compile-time map
// default value is false_type = no relation
template <typename I,typename ROLE>
constexpr std::false_type make_association;
// isAssociated used as a compile-time "function"
template <typename I, typename R>
using isAssociated = decltype(make_association<std::decay_t<I>,std::decay_t<R>>);
template <typename I, typename ROLE>
void install( I &&i, ROLE r)
{
static_assert(isAssociated<I,ROLE>(), "make_association<I, ROLE> not registered");
static_assert(std::is_enum_v<ROLE> || std::is_integral_v<ROLE> );
std::cout<<"Entered install( I &&, ROLE r)"<<std::endl;
}
template <typename I>
void install( I &&i)
{
static_assert(isAssociated<I,void>(), "make_association<I, void> not registered");
std::cout<<"Entered install( I &&)"<<std::endl;
}
enum WrongIndexT { ok = 1};
enum IndexT { min=0, max=3 };
class ObjT final {};
// a class for which any index works
template <class T> class Any final {};
template <class T, class Index>
constexpr std::true_type make_association<Any<T>, Index>;
// here the relations are set using variable template specialization;
template<> constexpr std::true_type make_association<ObjT, IndexT>;
template<> constexpr std::true_type make_association<ObjT, void>;
int main() {
ObjT f1,f2,f3;
install(f1, IndexT::min);
install(f2);
install(Any<int>{}, WrongIndexT::ok); // OK
install(f1, WrongIndexT::ok); // compilation error
return 0;
}

How do I statically check my templated class at definition time?

In C# or Java, the following does not compile, because I "forgot" the where part in class declaration, that specifies that T is instance of something that defines the add method.
class C<T> {
T make(T t) {
return t.add(t);
}
}
I'd like to get similar compile-time check in C++, if I specify incomplete requires for a template argument.
template <typename T>
requires true
class C {
public:
T make() {
return T{};
}
};
I'd like to get a compile error for the C++ code above, stating that method c.make relies on T being default-constructible, which is however not captured in the requires constraints on T.
Can I get the compiler to check that my set of requires constraints is sufficient to cover everything the class implementation does?
I am using gcc (GCC) 10.0.0 20191207 (experimental) for this.
What I want is called definition checking, and apparently it is not possible currently
C++2a concepts (formerly known as “Concepts Lite” and/or the Concepts TS) famously do not support “definition checking.” The idea of definition checking is that the programmer might write [...]
https://quuxplusone.github.io/blog/2019/07/22/definition-checking-with-if-constexpr/
8.2 Definition checking
Concepts currently do not prevent a template from using operations that are not specified in the requirements. Consider:
template<Number N>
void algo(vector<N>& v){
for (auto& x : v) x%=2;
}
Our Number concept does not require %=, so whether a call of algo succeeds will depend not just on what is checked by the concept, but on the actual properties of the argument type: does the argument type have %=? If not, we get a late (instantiation time) error.
Some consider this a serious error. I don’t [...]
http://www.w.stroustrup.com/good_concepts.pdf
The current proposal checks interfaces and that's where the main benefits for users are, but not template definitions. That has been explicit from the start.
https://isocpp.org/blog/2016/02/a-bit-of-background-for-concepts-and-cpp17-bjarne-stroustrup
template <class T>
requires std::is_default_constructible_v<T>
class C
{
static_assert(std::is_default_constructible_v<T>,
"T is not default-constructible");
};
struct valid
{
};
class invalid
{
invalid() = delete;
};
int main()
{
C<valid>();
// C<invalid>(); // assertion fails.
}
You can write static_assert anywhere inside the class definition, alongside with requires. That will give you an error message you want.
UPDATE After reading the link you have provided, I suppose you just need multiple checks.
You can write a traits struct:
// SFINAE to check if has "add"
template <class T, class = std::void_t<>>
struct has_method_add
{
constexpr static bool value = false;
};
template <class T>
struct has_method_add<T, std::void_t<decltype(&T::add)>>
{
constexpr static bool value = true;
};
template <class T, class = std::void_t<>>
struct has_operator_remainder
{
constexpr static bool value = false;
};
template <class T>
struct has_operator_remainder<T, std::void_t<decltype(&T::operator%=)>>
{
constexpr static bool value = true;
};
template <class T>
struct error_missing_add
{
constexpr static bool value = has_method_add<T>::value;
static_assert(has_method_add<T>::value, "T::add is not defined");
};
template <class T>
struct error_missing_remainder
{
constexpr static bool value = has_operator_remainder<T>::value;
static_assert(has_operator_remainder<T>::value, "T::operator%= is not defined");
};
template <class T>
class C
{
static_assert(std::conjunction_v<error_missing_add<T>, error_missing_remainder<T>>);
// impl...
};
struct valid
{
void add();
int operator%=(int) const;
};
struct missing_add
{
int operator%=(int) const;
};
struct missing_remainder
{
void add();
};
int main()
{
C<valid>{};
C<missing_add>{}; // error: T::add is not defined
C<missing_remainder>{}; // error: T::operator%= is not defined
return 0;
}

C++, Apply template pattern to function selectively

I have a class that can either be constructed by arguments of "ordinary" types, int, string, etc., or that can be constructed by a couple of different 'special' types invented by a coworker.
The 'special' types have the same signature, but aren't in a parent-child relationship.
So the code I have now looks something like:
class my_nifty_class {
public:
// "ordinary" constructor
template <class T> my_nifty_class(T) {some generic code}
// "special" constructors
my_nifty_class(my_first_clever_class) {
some clever code
}
my_nifty_class(my_second_clever_class) {
the identical clever code
}
In order to avoid duplicating some clever code (and opening myself up to the risk of not always duplicating it right), I would like to replace this with
class my_nifty_class {
public:
// "ordinary" constructor
template <class T> my_nifty_class(T) {some generic code}
// "special" constructors
template <class clever_class> my_nifty_class(clever_class) {
/**** I need template magic somewhere around here ****/
some clever code
}
But -- I don't know the template magic to put in there, or if there is any such magic to be had. I know I could do it if I were declaring classes -- but I'm declaring functions, so I'm kinda stuck.
You want std::enable_if, and you want some compile-time property of your special classes that other classes don't have.
template <class T, class S = std::enable_if_t<!is_my_special_v<T>>>
my_nifty_class(T) {some generic code}
template <class T, class S = std::enable_if_t<is_my_special_v<T>>, bool = true>
my_nifty_class(T) {some special code}
(The dummy template parameter is needed to make the two templates distinct)
Another method is to have just one constructor and use the special selector inside.
template <class T>
my_nifty_class(T) {
if constexpr(is_my_special_v<T>)
some special code
else
some generic code
}
How do you write is_my_special_v? It is just a template with the value of false, with specialisations for your special types with the value of true.
template<class> constexpr bool is_my_special_v = false;
template<> constexpr bool is_my_special_v<MySpecialType1> = true:
// ...
If all your special classes have some member name that is unlikely to occur in non-special classes, you can use that in order to write just one specialisation of is_my_special_v total instead of one per special class. Search for "c++ member detection", lots of material out there.
Finally, if this is the only place where your special types are indeed special, you can skip
is_my_special_v altogether and just check directly.
template <class T>
my_nifty_class(T) {
if constexpr(std::is_same_v<T, MySpecialType1> ||
std::is_same_v<T, MySpecialType2> ...)
some special code
else
some generic code
}
Here is my go at the answer. You will just share a generic constructor for all types. And handle the logic within the constructor using std::is_pod which was introduced in c++11 I believe.
Essentially POD (plain old data) types such as; int, float, double, etc. will be handled by one templated function, and any complex/non-trivial data types will be handled by your other templated function.
class my_nifty_class {
public:
template<class T> handle_pod_type(T value)
{ /* Code to handle POD data types */ }
template<class SpecialType> handle_special_type(SpecialType value)
{ /* Code to handle complex data types */ }
template <class T> my_nifty_class(T value) {
if( std::is_pod<T>::value ) {
handle_pod_type(value);
}
else {
handle_special_type(value);
}
}
}
Also take note of what is_pod is doing and what classifies a POD type in C++11.
I suggest that you can use "tag structures" and class template specializations to solve your problem:
struct TypeA {};
struct TypeB {};
struct TypeC {};
class Class {
public:
template<class T> Class(T val) : Class(typename SelectTag<T>::Type{}, val) {}
private:
struct GenericTag {};
struct BOrCTag {};
template<class T> struct SelectTag { using Type = GenericTag; };
template<class T> Class(GenericTag, T val) { /* do smth */ }
template<class T> Class(BOrCTag, T val) { /* do smth else */ }
};
template<> struct Class::SelectTag<TypeB> { using Type = BOrCTag; };
template<> struct Class::SelectTag<TypeC> { using Type = BOrCTag; };

how to use enable_if with overloads

enum class enabler{};
template<typename T>
class X {
template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()>
void func();
void func(int a);
void func(std::string b);
};
I have this class with these 3 overloads for func. I need the second/third versions to be available for both class/non-class types, and the first version to be available only for class types. when I tried to use enable_if as above, the class instantiation for non-class types gives compile error.
For SFINAE to work, the template argument must be deduced. In your case, T is already known by the time you attempt to instantiate func, so if the enable_if condition is false, instead of SFINAE, you get a hard error.
To fix the error, just add a template parameter whose default value is T, and use this new parameter in the enable_if check. Now deduction occurs and SFINAE can kick in for non-class types.
template<typename U = T,
typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()>
void func();
And you don't really need a dedicated enabler type either, this works too
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
I'm not really sure what you're going for with enabler here, but you can't do what you're trying because the declaration for your member function must be valid since T is not deduced by func. To achieve what you want in adding an extra overload, you can use some moderately contrived inheritance.
struct XBaseImpl {
// whatever you want in both versions
void func(int a) { }
void func(std::string b) { }
};
template <typename, bool> struct XBase;
// is_class is true, contains the extra overload you want
template <typename T>
struct XBase<T, true> : XBaseImpl {
static_assert(std::is_class<T>{}, ""); // just to be safe
using XBaseImpl::func;
void func() { } // class-only
};
// is_class is false
template <typename T>
struct XBase<T, false> : XBaseImpl { };
template<typename T>
class X : public XBase<T, std::is_class<T>{}> { };
You are not enabling or disabling something.
You simply want a compile time error in one specific case.
Because of that you don't require to rely on sfinae, a static_assert is enough.
As a minimal, working example:
#include<string>
template<typename T>
class X {
public:
void func() {
static_assert(std::is_class<T>::value, "!");
// do whatever you want here
}
void func(int a) {}
void func(std::string b) {}
};
int main() {
X<int> x1;
X<std::string> x2;
x2.func(42);
x2.func();
x1.func(42);
// compilation error
// x1.func();
}
Once a SO user said me: this is not sfinae, this is - substitution failure is always an error - and in this case you should use a static_assert instead.
He was right, as shown in the above example a static_assert is easier to write and to understand than sfinae and does its work as well.

Prevent templated member function from being instantiated for a given type

I have a templated matrix class that I explicitly instantiate for various POD types and custom class types. Some of the member functions however don't make sense for a few of such custom types. For example:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types? So far I have avoided the issue by making LoadFile a friend function and then explicitly controlling its instantiation. But I want to know if I can do this when LoadFile is a member function of Matrix.
The first question is whether you really need to control this. What happens if they call that member function on a matrix that stores My_custom_class? Can you provide support in your class (or the template) so that the member function will work?
If you really want to inhibit the use of those member functions for some particular type, then you can use specialization to block the particular instantiation:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
Or even just add static_asserts to the common implementation verifying the preconditions for what types is it allowed or disallowed?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
with std::enable_if, this is the best I can come up with
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
only type int compile while other don't.
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types?
Your best bet here would be to use a static_assert that would create a compiler error when you attempt to call the method in a version of the class instantiated with a blocked type. Using std::enable_if, and other methods that would selectively "disable" a method itself would require you to create partial or full specializations of the class with and without the methods in question in order to prevent compiler errors. For instance, AFAIK, you cannot do the following:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
If you attempted to instantiate an example<int>, etc., you would end up with a compiler error at the point of instantiation of the object type. You couldn't simply call example<int>::print() and be okay, and only run into a problem if you chose to call example<int>::another_print(). Specializations of example<T> could get you around the issue, but that can be a bit of a mess. As originally surmised, a static_assert would probably be the easiest case to handle, along with a nice message to the end-user explaining what went wrong.
Keep in mind that creating compiler errors is the goal, and it's a good one to have. If you blocked a method from being instantiated, and the end-user decided to invoke it, you'd end up with a compiler error either way. The version without the static_assert will leave a lot of head-scratching as the user of your class attempts to parse a probably very verbose compiler error message, where-as the static_assert method is direct and to the point.
If the selected set of types is known at compile time, and you are using c++11 with a compiler that supports type aliases, uniform initialization and constexpr (for example gcc 4.7) you can make your code a bit cleaner like this (from previous example above by yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
Beware of compatibility of this code, though, because these features have been only recently supported and some compilers don't do yet. You can see more about c++11 compiler support here.
If you could use the TypeLists from the ( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Loki you could implement something like:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
Then your HasType would be something like:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
In the list you can add the classes which you would like prevent to be passed as the template parameters.