Hello Stackoverflow community,
I've been really confused on the concepts syntax and am having a hard time getting started.
I would like to create a polymorphic interface for two types of operator types: unary and binary and opted to try out the concept feature in c++20.
Not sure if it matters, but I used a CRTP create my unary functor compatible with binary functors, however I would like to get rid of that. Here's what I have so far:
template <typename T>
concept UnaryMatrixOperatable = requires(T _op) {
_op.template operate(std::unique_ptr<Matrix::Representation>{});
{_op.template operate() } -> same_as<std::unique_ptr<Matrix::Representation>>;
};
class ReLU : public UnaryAdapter<ReLU> {
public:
std::unique_ptr<Matrix::Representation> operate(
const std::unique_ptr<Matrix::Representation>& m);
};
static_assert(UnaryMatrixOperatable<ReLU>);
However, I am getting a compilation error, presumably because I am not doing some sort of template specialization for a const matrix & type?
include/m_algorithms.h:122:13: error: static_assert failed
static_assert(UnaryMatrixOperatable<ReLU>);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/m_algorithms.h:122:27: note: because 'Matrix::Operations::Unary::ReLU' does not satisfy 'UnaryMatrixOperatable'
static_assert(UnaryMatrixOperatable<ReLU>);
^
include/m_algorithms.h:53:26: note: because '_op.template operate(std::unique_ptr<Matrix::Representation>{})' would be invalid: 'operate' following the 'template' keyword does not refer to a template
_op.template operate(std::unique_ptr<Matrix::Representation>{});
^
Thanks for all the help in advance, this design in my code has been problematic for over a week so I'm determined to find a clean way to fix it! Thanks.
Concepts are not base classes, and you should not treat concept requirements like base class interfaces. Base classes specify exact function signatures that derived classes must implement.
Concepts specify behavior that must be provided. So you explain what that behavior is.
The behavior you seem to want is that you can pass an rvalue of a unique pointer to an operate member function. So... say that.
template <typename T>
concept UnaryMatrixOperatable = requires(T _op, std::unique_ptr<Matrix::Representation> mtx)
{
_op.operate(std::move(mtx));
};
There's no need for template here because you do not care if operate is a template function. It's not important in the slightest to your code if any particular T happens to implement operate as a template function or not. You're going to call it this way, so the user must specify some function interface that can be called a such.
The same goes for the zero-argument version. Though your interface should probably make it much more clear that you're moving from the unique pointer in question:
template <typename T>
concept UnaryMatrixOperatable = requires(T _op, std::unique_ptr<Matrix::Representation> mtx)
{
_op.operate(std::move(mtx));
{ std::move(_op).operate() } -> std::same_as<decltype(mtx)>;
};
In any case, the other reason you'll get a compile error is that your interface requires two functions: one that gets called with an object and one that does not. Your ReLu class only provides one function that pretends to do both.
Related
Since we define the template type over the class declaration, why do we have to specify it after each function definition? I'm confused because its even in the same file so it seems almost unnecessary to have to specify it over every function and because we are using the :: operator shouldnt it go back to the class declaration and see that T is already defined.
I'm new to c++ and still need to clear up some misunderstandings.
#ifndef __Foo_H__
#define __Foo_H__
template <class T>
class Foobar{
private:
bool foo1(T);
bool foo2(T);
public:
FooBar();
};
template <class T> bool FooBar<T>::foo1(T data){
code..
}
template <class T> bool FooBar<T>::foo2(T data){
code..
}
#endif
First you may rename the argument as for normal function:
template <class U> bool FooBar<U>::foo1(U and_here_too){/**/}
It also manages to handle (partial) specialization:
template <> bool FooBar<int>::foo1(int i){/**/}
template <typename T> bool FooBar<std::vector<T>>::foo1(std::vector<T> v){/**/}
Templates are example of generic programming. The idea is to reuse code/algorithms. In languages with strict type control you come across seemingly unnecessary constraints. For instance you may have some sorting function doing great job in one project but incompatible with types used in another.
C++, C#, and Java introduce generic programming as templates (C++) and generics (C#, Java). In generics (let's talk about Java) classes are existing entities and class parameters serve mainly as type control service. That is their purpose in collections. When you inspect how list works you see list gathers Objects and cast back to the parameterized type only when the object is retrieved. When you write class you can only assume the parameterized type is Object or declared interface like in the following example:
class Test<T extends Comparable> {}
Here you can use T as Comparable. Unless you explicitly declare the interface, the parameter is treated as Object.
Now comes the difference between generics and templates. In C++ you can assume much more about the parameterized type in implementation. You can write sorting of objects of unknown type. In Java you have to at least know what is interface the parameter type. This causes that C++ have to build new class for each parameter (in order to check if the code is correct). Vector<int> **is completely separate type from **Vector<float>. While in Java there exists one class Vector<? extends Comparable>.
:: is scope operator. You can access scope of Vector<int> because the class exists, however, Vector does not.
As a result Java can compile generics and C++ cannot. All templates have to be available in headers to all programmers; you cannot hide it (there is some work to compile templates but I don't know what is its status).
So when you use generics you can refer to method Vector.add() while when templates you have to specify parameter template<class T> Vector<T>.
PS. since template parameter is integral part of class name you may use templates for compile time calculations like fibonaci sequence
template<int N> struct Fibonaci {
static const int element = Fibonacci<N-1>::data + Fibonacci<N-2::data>;
}
template<1> struct Fibonaci {
static const int element = 1;
}
template<0> struct Fibonaci {
static const int element = 0;
}
I was perusing the (MSVC++ 2010) limits header for knowledge purposes and noticed this little gem:
template<class _Ty>
class numeric_limits
: public _Num_base
{
//...Insert min, max, lowest, epsilon,
//round_error, denorm_min, infinity, quiet_Nan, and signaling_Nan
//that return _Ty(0).
//In other words, this class does "nothing" in a "safe" manner.*
};
Followed promptly by:
template<class _Ty>
class numeric_limits<const _Ty>
: public numeric_limits<_Ty>
{ // numeric limits for const types
};
template<class _Ty>
class numeric_limits<volatile _Ty>
: public numeric_limits<_Ty>
{ // numeric limits for volatile types
};
template<class _Ty>
class numeric_limits<const volatile _Ty>
: public numeric_limits<_Ty>
{ // numeric limits for const volatile types
};
What purpose does an empty class provide? Why write it? I understand the purpose in this case with templates because of template specialization and the possibility of a constant, volatile, or constant-volatile non-fundamental type being passed in; however, in the case of non-template usage, what purpose does it provide?
*"nothing" and "safe" are subjective terms in this case and their layman definitions are to be applied only if the reader knows without a doubt that they truly do nothing and are safe. I do not, hence the disclaimer.
The standard requires that numeric_limits<const int> returns the same results as numeric_limits<int>. The standard library authors could either duplicate all the implementation, or define one in terms of the other.
What purpose does an empty class provide? Why write it?
It's not an empty class, it has all the same members as its base class. This is known as implementation inheritance.
There are good reasons to define empty types, e.g. for tag dispatching but that is not relevant here, because those numeric_limits partial specializations don't make empty classes anyway.
I'm not sure there's a question to answer, here. In your question, you already state that you understand why it was done in this case. It sounds like you're asking us to explain why it would be done in some other hypothetical case which doesn't actually exist.
In order to know why an empty class might be useful for some other case, we'd need a real example where an empty class was used, I think.
I have stumbled many times on classes defined like
class PureVirtualClass
{
virtual int foo() = 0;
virtual bool bar() = 0;
}
template <class T> class ImplClass : public virtual PureVirtualClass
{
virtual ~ImplClass(){};
int foo() { return 42;}
bool bar() { return true;}
//several other method having nothing to do with T
}
This "design" appears so often I want to think the original developer knew what he was doing by defining ImplClass as template class but without any reference to the template argument T anywhere. My own c++ template knowledge is kinda limited.
Is there a benefit to this or is it just a confused programmer?
There can be a benefit for classes being templated but not depending on the argument. Most often you see such things to define (empty) tag-structures for template metaprogramming:
template <class X>
struct some_tag {};
The benefit of classes like yours in general is that while you have the same functionality in each class, they are different classes and you can't copy one into the other, i.e. an object of type ImplClass<int> is not compatible with another object of type ImplCalss<float>.
There are many useful cases of the idea mentioned by Arne. For instance, looking at Very basic tuple implementation, this is how a single tuple element is defined:
template <size_t N, typename T>
class TupleElem
{
T elem;
public:
T& get() { return elem; }
const T& get() const { return elem; }
};
It is templated on N, without depending on it. Why? Because the tuple implementation
template <size_t... N, typename... T>
class TupleImpl <sizes <N...>, T...> : TupleElem <N, T>...
{
//..
};
derives multiple such elements, each with a unique N, serving as an identifier. Without it, TupleImpl would be deriving the same class twice, had two element types been identical within parameter pack T.... Neither random access to elements would work in this case (via an explicit call of function get() of the appropriate TupleElem base class, which would be ambiguous), nor empty base optimization (via specializing TupleElem for empty types T to not have a data member of type T).
This is a real use case, and exactly how std::tuple is implemented by clang. Of course, a class like TupleElem would be a hidden implementation detail, and not part of the interface. For instance, gcc follows an entirely different recursive class design.
In general, you will need to study the context where classes are used to understand the intent of the designer.
maybe that developer simply is too lazy to split the classes into .h and .cpp files?
Without using templates, linker errors would occur if the classes are used in multiple compilations units. When using templates, the linker usually discards duplicate instantiations of a template at link time (or handles the problem in a different way).
While this may be an answer to "why did the developer do this", I would not recommend this if the question was "when should I introduce template arguments which are never used" (see the other answers for this). Even though it is annoying to split code into .h and .cpp (especially when used to languages like Java or C#), it's the usual C++ way. And it is definitely easier to read/understand than using templates only for this purpose. Also, it makes the use of the classes less readable.
I try to implement a template class which requires to have a signal member that depends on the template argument. My first idea was to realize it like the following:
template<class T>
class SignalClass
{
typedef boost::signals2::signal<void (T &)> OnReceive;
public:
SignalClass(const OnReceive::slot_type &_slot)
{
m_onReceive.cnnect(_slot);
}
virtual SignalClass(){};
void Send(T &_val)
{
m_onReceive(_val);
}
private:
OnReceive m_onReceive;
};
An that class should be used like:
class SignaledClass
{
public:
SignaledClass(void)
{
SignalClass<int> var1(boost::bind(&SignaledClass::ReceiveINT, this));
SignalClass<double> var2(boost::bind(&SignaledClass::ReceiveDOUBLE, this));
}
void ReceiveINT(int &_val)
{
...
}
void ReceiveDOUBLE(double &_val)
{
...
}
}
(BTW: I know, that it makes no sense to create the SignalClass object just inside the constructor. It's just to understand my problem.)
It is important for me to realize a delegate-like concept with a template as signal parameter.
The problem is that the constructor code doesn't work.
But I found a solution.
If I additionally specify an additional typedef like
typedef typename OnReceive::slot_type slot_type;
and use that a parameter for the constructor, like
PushInputSlot(const slot_type& _slot);
the it works.
But I have no real clue why.
I hope that somebody can help me.
Thanx,
Frank
P.S.: I'm new on stackoverflow thats why I'm not familiar with the rules here. Hope I've done everything in the right way... ;-)....
Here is the reason why adding typename (either directly in the constructor argument or in an additional typedef) works:
First, the type OnReceive is a so-called "dependent type", because it depend on the type of the template parameter.
Then, templates are processed in two stages in the compiler: The first stage is when the compiler encounters the source text for the template and the second stage is when the template is actually instantiated.
During the first stage of processing, the compiler will (should) try to validate as far as possible that the template definition is correct, but it runs into a problem when it comes to dependent types. Because a dependent type depends on the template parameters, the compiler does not know what the actual type will look like.
In particular, when accessing a member with the :: operator, the compiler needs some help deciding if the member is expected to refer to a member-type (typedef or nested class) or a non-type member (a variable, enum, etc.). This can be resolved by adding typename before the (full) type-name if you know that it should refer to a type.
The other place where the compiler might have a problem is differentiating between a member-template and a non-template member involved in a less-than comparison. This is resolved by adding the keyword template before the name of the member-template (immediately after the operator).
I'm trying to find is there's a way to check if a class is a functional because i want to write a template which uses it?
Is there an easy way to do this? Or do I just wrap things in a try/catch? Or perhaps the compiler won't even let me do it?
If you have a function template written like:
template <typename T>
void f(T x)
{
x();
}
you will be unable to instantiate it with any type that is not callable as a function taking no arguments (e.g., a class type that overloads operator() taking no arguments is callable as a function that takes no arguments). You would get a compilation error if you tried to do so.
This is the simplest way to require the type with which a template is instantiated to have certain properties: just rely on the type having those properties when you write the template, and if the type doesn't have one of the required properties, it will be impossible to instantiate the template with that type.
There are quite a few ways a parameter type can be applicable to the call syntax
Type is a pointer or reference to a function type, or
Type is a class-type which has a conversion function to one of the types in 1., or has an applicable operator().
The current C++ cannot check for 2., so you are left without checking, like the other answers explain.
This would fall under doing it and getting a compiling error. When the code is compiled the template function or template classes are are expanded for the types used as if there were duplicate copies of that template code, one for each type.
So you can basically do whatever and as long as all the types used for your templates support it you have no problem. If they don't support it you have a compiling error and you can't run your code without fixing it.
template <typename T>
void DoIt(T a)
{
a.helloworld();//This will compile fine
return a();//This will cause a compiling error if T is B
}
class A
{
public:
void a.helloworld(){}
void operator()(){}
};
class B
{
public:
void a.helloworld(){}
};
int main(int argc, char**argv)
{
A a;
B b;
DoIt(a);
DoIt(b);//Compiling error
return 0;
}
If you actually need a test to see if type T implements an operator() of some given signature then you could use the same SFINAE trick used to identify the existence of any other class member that is discussed here: C++ "if then else" template substitution