I only have an hpp file for a school assignment in C++ (I am not allowed to add a cpp file, declaration and implementation should be both written in the file).
I wrote this code inside it:
template<class T>
class Matrix
{
void foo()
{
//do something for a T variable.
}
};
I would like to add another foo method, but this foo() will be specialized for only an <int>.
I have read in some places that I need to declare a new specialization class for this to work. But what I want is that the specialized foo will lie just beneath the original foo, so it will look like this:
template<class T>
class Matrix
{
void foo(T x)
{
//do something for a T variable.
}
template<> void foo<int>(int x)
{
//do something for an int variable.
}
};
Why am I getting an error for this syntax ("expected unqualified-id before '<' token")?
Why isn't this possible?
How can I fix this without declaring a new specialized class?
Thanks
foo isn't a template. It's a member function of a template. Thus foo<int> is meaningless. (Also, explicit specializations must be declared at namespace scope.)
You can explicitly specialize a member function of a particular implicit instantiation of a class template:
template<class T>
class Matrix
{
void foo(T x)
{
//do something for a T variable.
}
};
// must mark this inline to avoid ODR violations
// when it's defined in a header
template<> inline void Matrix<int>::foo(int x)
{
//do something for an int variable.
}
You need to define the original foo method as a template, and actually there is no need for your class to be a template, only the method:
class Matrix
{
template<typename T> void foo(T x)
{
//do something for a T variable.
}
template<> void foo<int>(int x)
{
//do something for an int variable.
}
};
UPDATE: The code works only in Visual Studio. Here is a code that should work elsewhere too:
class Matrix
{
template<typename T> void foo(T x)
{
//do something for a T variable.
}
};
template<> void Matrix::foo<int>(int x)
{
//do something for an int variable.
}
Related
I would like to conditionally declare a local variable in a function, based on a template bool parameter. So if it is true it should be there, otherwise shouldn't be there in the sense that I don't want that variable to allocate memory on the stack or call its constructor. It could also be a basic type.
I cannot declare it within the constexpr if block because I need persistence between the usages.
I can just declare the variable and add [[maybe_unused]]. Then, is there a compiler optimization which guaranties not to allocate memory for the variable?
template <bool T> void foo()
{
[[maybe_unused]] SomeLargeClass x;
if constexpr(T)
{
... do something with x
}
... do something without x
if constexpr(T)
{
... do something more with x
}
}
I tried to replace the declaration with
std::enable_if_t<T, SomeLargeClass> x;
but it doesn't work because the T==false case fails to provide a type. Why is this not SFINAE?
Do I have any other options?
As-if rule might discard unused SomeLargeClass, but it is more complicated if that class do allocations.
One easy trade-of is to use std::conditional and have SomeLargeClass when needed, and some dummy small class in other case;
struct Dummy
{
// To be compatible with possible constructor of SomeLargeClass
template <typename ...Ts> Dummy(Ts&&...) {}
};
template <bool B> void foo()
{
[[maybe_unused]] std::conditional_t<B, SomeLargeClass, Dummy> x;
if constexpr(B) {
// ... do something with x
}
// ... do something without x
if constexpr(B) {
// ... do something more with x
}
}
Yes, compilers can optimize unused variables, supposed it can proove that construction and destruction has no observable side effects.
It is not SFINAE, because not a type x; makes the whole function fail. There is no alternative foo, hence it is a hard error.
Yes, you can specialize foo:
.
struct SomeLargeClass {};
template <bool T> void foo();
template <> void foo<false>() {
//... do something without x
}
template <> void foo<true>() {
SomeLargeClass x;
//... do something with x
foo<false>();
//... do something more with x
}
You could use the local variable x, but give it a specialized type:
#include <iostream>
using std::ostream;
template <bool T> struct MaybeLargeType;
template <> struct MaybeLargeType<true> { int bigone; };
template <> struct MaybeLargeType<false> {};
ostream& operator<<(ostream& s, const MaybeLargeType<true>& o) { return s << o.bigone; }
ostream& operator<<(ostream& s, const MaybeLargeType<false>& o) { return s << "nope"; }
template <bool T> void foo() {
MaybeLargeType<T> x;
if constexpr(T) {
x.bigone = 1;
}
// other stuff
if constexpr(T) {
x.bigone += 3;
}
std::cout << x;
}
int main()
{
foo<true>();
foo<false>();
return 0;
}
This moves the LargeType inside variable x, which is big-or-small depending on the template parameter, so your code in the if constexpr blocks is slightly more wordy.
Just a variant of the specialisation approach:
template <bool B>
class C
{
public:
void step1() { };
void step2() { };
};
template <>
class C<true>
{
public:
void step1() { /* use the large data*/ };
void step2() { /* use the large data*/ };
private:
// large data
};
template <bool B>
void foo()
{
C<B> x;
x.step1();
// x-unaware code
x.step2();
}
Which one looks better? Just a pure matter of taste...
I'll leave finding better names to you.
If your class has a trivial constructor, just don't worry - the compiler will not allocate an unused object on stack.
If your class has a constructor which does some work, you might want to skip this work if you know it's wasted. The compiler might still notice that the object is unused, and skip the constructor. Check this before you do any changes to your code (premature optimization)!
But if the constructor has some side-effects (not recommended), you have to help the compiler. One way to do it is by using unique_ptr:
template <bool T> void foo()
{
unique_ptr<SomeLargeClass> x;
if constexpr(T)
{
... allocate x
... do something with *x
}
... do something without x
if constexpr(T)
{
... do something more with *x
}
}
I don't have a lot of experience with templates but I am wondering if the following scenario is possible. Assume we have a class S with static member stat. I can get it to dynamically generate different code using typeid as:
template <class S>
void foo()
{
if (typeid(S::stat) == typeid(AType))
implementation 1;
else
implementation 2;
}
But since all information is known at compile time is it possible to create a specialization of foo for S::stat being of type Atype?
You're probably looking to do something like this:
template<typename T> class foo_impl {
public:
static void foo()
{
// This is your implementation 2
}
};
template<> class foo_impl<AType> {
public:
static void foo()
{
// This is your implementation 1
}
};
template <class S>
void foo()
{
foo_impl<typename S::Stat>::foo();
}
One common way of solving this problem is through tag dispatching. We can, at compile time, produce different types for whether or not S::stat matches AType - and use those types to call different overloads:
template <class S>
void foo() {
foo_impl(std::is_same<decltype(S::stat), AType>{});
}
void foo_impl(std::true_type /* S::stat matches AType */) {
// implementation 1
}
void foo_impl(std::false_type /* S::stat doesn't match AType */) {
// implementation 2
}
I was not able to utilize the decltype solution because my compiler does not support it.
I was able to utilize the foo_impl class solution but only when I declare MyClass as:
class MyClass {
public:
typedef AType Stat;
static const Stat stat = VAL;
...
}
I have a template like:
template <typename T>
class MyThing {
public:
static void Write(T value) { ... }
static void Flush() { ... }
}
For a specific type, eg bool, I want to specialize the Write method without modifying the other methods. Something like this...
// Specialize Write() behavior for <bool> ...
// This won't work. Mything<bool> no longer has a Flush() method!
template <>
class MyThing<bool> {
public:
static void Write(bool value) { ... }
}
How do I specialize just one of the methods in a template class?
The fix for this turns out to be simple ...
All I need to do is to define the method in my .cc file:
template <>
void MyThing<bool>::Write(bool value) { ... }
And then declare it in my .h file:
template <>
void MyThing<bool>::Write(bool value);
It took me a while to figure this out, so I thought I'd post it.
Say I declared a class with a template method.
class MyClass {
...
template<typename T> void myMethod(const T& obj);
}
I have defined a generic version of the method
template<typename T>
void MyClass::myMethod(const T& obj) { .... }
and want to define several specializations for various types. What is the correct syntax? VS2013 compiler does not seem to approve my attempts.
template<>
void MyClass::myMethod<int>(const int &) {....}
or
template<int>
void MyClass::myMethod(const int &) { .... }
The first syntax is ok, as a specialization. The second is wrong as it is defining a template<int> while myMethod is declared as a template<typename>. But keep in mind that a specialization isn't needed at all, an overload is just fine, like
class MyClass {
void myMethod(const int& obj) { ... }
// ... more overloads
};
Of course, if you need to separate declarations from definitions (which I avoid for templates), this leads to more code duplication. Depending on type, this way you may also enforce call by value, e.g.
void myMethod(bool obj) { ... }
which does not apply to your specializations.
I have the following functions in class "C"
class C
{
template<typename T> void Func1(int x);
template<typename T> void Func2(int x);
};
template<typename T> void C::Func1(int x)
{
T a(x);
}
template<typename T> void C::Func2(int x)
{
T a(x);
}
The functions uses templates only in the implementation. The signature does not contain template parameters.
Is it possible to define pointers to such template functions?
I tried the following definition but it results compilation error.
typedef template<typename T> void (СSomeClass::*TFuncPtr)(int);
Once instantiated, a member function template is just a normal member function, so you can use a normal member function pointer (best typedef'd like below):
typedef void (C::*mem_fun_ptr)(int);
mem_fun_ptr p = &C::Func1<Bar>;
// IMPORTANT -- ^^^^^
The underlined part is the important part. You can't make a pointer to a function template, but you can make a pointer to an instantiated function template.
do you want only a pointer to a function?
that's simple:
class C
{
public:
template<typename T> void Func1(int x);
};
typedef void (C::*TFuncPtr)(int);
int main()
{
TFuncPtr ptr = &C::Func1<int>;
}
if you want something else could you show an example of using the pointer you want?