Template Function Specialization - c++

I am doing an exercise on templates and I am now dealing with specializations. I have defined a function T read_val(T& v) that takes input from cin and compiles the T val inside my template<typename T> struct S. I wish to specialize this function to types int, double, char, string but, when I am trying to do it, I'm keep getting errors. Here is what I wrote:
Header.h:
#ifndef Templates_Header_h
#define Templates_Header_h
#include <iostream>
using namespace std;
template<typename T>
struct S
{
private:
T val;
public:
S() : val{} {};
T* get();
T* get() const;
T set();
T operator=(const T&);
T read_val(T& v);
void print_val() const;
};
template<typename T>
void S<T>::print_val() const
{
cout << "Value is: " << val << endl;
}
template<typename T>
T* S<T>::get()
{
T* p = &val;
return p;
}
template<typename T>
T S<T>::set()
{
T newvalue;
cout << "Type new value: ";
cin >> newvalue;
S<T>::val = newvalue;
return S<T>::val;
}
template<typename T>
T S<T>::operator=(const T&)
{
T val1;
val1 = val;
return *this;
}
template<typename T>
T* S<T>::get() const
{
T* p = &val;
return p;
}
template<typename T>
T S<T>::read_val(T &v)
{
cout << "Type Value: ";
cin >> v;
return S<T>::val = v;
}
#endif
Header.cpp
#include <stdio.h>
#include "Header.h"
#include "std_lib_facilities.h"
template <>
struct S <int> // Specialization
{
private:
int val;
public:
S() : val{0} {};
};
template<>
struct S<char> // Specialization
{
private:
char val;
public:
S() : val{'0'} {};
};
template <>
struct S<double> // Specialization
{
private:
double val;
public:
S() : val{0.0} {};
};
template <>
struct S<string> // Specialization
{
private:
string val;
public:
S() : val{""} {};
};
template<>
struct S<vector<int>> // Specialization
{
private:
vector<int> val;
public:
S() : val{0} {};
};
template<> // !! ERROR !!
int read_val(int& v)
{
cout << "Type a value: ";
cin >> v;
return v;
}
Xcode is reporting "No function template matches function template specialization 'read_val'". I was surfing the net reading examples and references but I cannot solve it. Can you help me? I need an example to fix it in mind.
Thanks!

There should be no CPP file for a template header. Your implementation is already in the header file!
Create main.cpp with:
#include "Header.h"
#include <iostream>
int main()
{
S<int> my_S;
int val;
my_S.read_val(val/*by ref*/);
std::cout << "The read value is " << val << std::endl;
return 0;
}
Or something like that, I didn't compile it...
According to your implementation I see that you missed the point of templates. You need to define it only once (no need to rewrite it manually for each type like int, float, etc., the compiler will do it for you).

Related

Template function deduction fail on std::conditional argument

Please, before marking this as a duplicate of This question read the entirety of the post
This piece of code fails to compile, with a template deduction error:
#include <iostream>
#include <type_traits>
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(MyType<TYPE> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
int main()
{
MyClass<float, 1> c;
c.Foo();
return 0;
}
I understand the point that was made in the question i linked above, which is that "the condition which allows to choose the type to be deduced depends on the type itself", however, why would the compiler fail in the specific case i provided as the condition here seems to be fully independent from the type, or is there something i'm missing?
I would be more than happy if someone could refer to a section of the c++ standard that would allow me to fully understand this behaviour.
As the linked question, TYPE is non deducible. MyType<TYPE> is actually XXX<TYPE>::type.
You have several alternatives, from your code, I would say one of
Bar no longer template:
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
void Bar(MyType<T> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
requires (or SFINAE/specialization for pre-c++20):
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(TYPE Input) requires(N > 0)
{
std::cout << typeid(Input).name() << std::endl;
}
void Bar(double Input) requires(N <= 0)
{
std::cout << typeid(Input).name() << std::endl;
}
};

Unify C++ templates for pointers, values and smart pointers

My real example is quite big, so I will use a simplified one. Suppose I have a data-type for a rectangle:
struct Rectangle {
int width;
int height;
int computeArea() {
return width * height;
}
}
And another type that consumes that type, for example:
struct TwoRectangles {
Rectangle a;
Rectangle b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Now, I don't want to put ownership constraints on users of TwoRectangles, so I would like to make it a template:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Usages:
TwoRectangles<Rectangle> x;
TwoRectangles<Rectangle*> y;
TwoRectangles<std::shared_ptr<Rectangle>> z;
// etc...
The problem is that if the caller wants to use pointers, the body of the function should be different:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
assert(a && b);
return a->computeArea() + b->computeArea();
}
};
What is the best way of unifying my templated function so that the maxiumum amount of code is reused for pointers, values and smart pointers?
One way of doing this, encapsulating everything within TwoRectangles, would be something like:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
return areaOf(a) + areaOf(b);
}
private:
template <class U>
auto areaOf(U& v) -> decltype(v->computeArea()) {
return v->computeArea();
}
template <class U>
auto areaOf(U& v) -> decltype(v.computeArea()) {
return v.computeArea();
}
};
It's unlikely you'll have a type for which both of those expressions are valid. But you can always add additional disambiguation with a second argument to areaOf().
Another way, would be to take advantage of the fact that there already is a way in the standard library of invoking a function on whatever: std::invoke(). You just need to know the underlying type:
template <class T, class = void>
struct element_type {
using type = T;
};
template <class T>
struct element_type<T, void_t<typename std::pointer_traits<T>::element_type>> {
using type = typename std::pointer_traits<T>::element_type;
};
template <class T>
using element_type_t = typename element_type<T>::type;
and
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
using U = element_type_t<T>;
return std::invoke(&U::computeArea, a) +
std::invoke(&U::computeArea, b);
}
};
I actually had a similar problem some time ago, eventually i opted not to do it for now (because it's a big change), but it spawned a solution that seems to be correct.
I thought about making a helper function to access underlying value if there is any indirection. In code it would look like this, also with an example similar to yours.
#include <iostream>
#include <string>
#include <memory>
namespace detail
{
//for some reason the call for int* is ambiguous in newer standard (C++14?) when the function takes no parameters. That's a dirty workaround but it works...
template <class T, class SFINAE = decltype(*std::declval<T>())>
constexpr bool is_indirection(bool)
{
return true;
}
template <class T>
constexpr bool is_indirection(...)
{
return false;
}
}
template <class T>
constexpr bool is_indirection()
{
return detail::is_indirection<T>(true);
}
template <class T, bool ind = is_indirection<T>()>
struct underlying_type
{
using type = T;
};
template <class T>
struct underlying_type<T, true>
{
using type = typename std::remove_reference<decltype(*(std::declval<T>()))>::type;
};
template <class T>
typename std::enable_if<is_indirection<T>(), typename std::add_lvalue_reference<typename underlying_type<T>::type>::type>::type underlying_value(T&& val)
{
return *std::forward<T>(val);
}
template <class T>
typename std::enable_if<!is_indirection<T>(), T&>::type underlying_value(T& val)
{
return val;
}
template <class T>
typename std::enable_if<!is_indirection<T>(), const T&>::type underlying_value(const T& val)
{
return val;
}
template <class T>
class Storage
{
public:
T val;
void print()
{
std::cout << underlying_value(val) << '\n';
}
};
template <class T>
class StringStorage
{
public:
T str;
void printSize()
{
std::cout << underlying_value(str).size() << '\n';
}
};
int main()
{
int* a = new int(213);
std::string str = "some string";
std::shared_ptr<std::string> strPtr = std::make_shared<std::string>(str);
Storage<int> sVal{ 1 };
Storage<int*> sPtr{ a };
Storage<std::string> sStrVal{ str };
Storage<std::shared_ptr<std::string>> sStrPtr{ strPtr };
StringStorage<std::string> ssStrVal{ str };
StringStorage<const std::shared_ptr<std::string>> ssStrPtr{ strPtr };
sVal.print();
sPtr.print();
sStrVal.print();
sStrPtr.print();
ssStrVal.printSize();
ssStrPtr.printSize();
std::cout << is_indirection<int*>() << '\n';
std::cout << is_indirection<int>() << '\n';
std::cout << is_indirection<std::shared_ptr<int>>() << '\n';
std::cout << is_indirection<std::string>() << '\n';
std::cout << is_indirection<std::unique_ptr<std::string>>() << '\n';
}

Check if object is instance of class with template

My class:
template < typename T >
Array<T>{};
(Source data is stored in vector)
I have an object:
Array< string > a;
a.add("test");
And I have an object:
Array< Array< string > > b;
b.add(a);
How can I check:
Is b[0] an instance of Array (regardless of template type)?
Is a[0] an instance of any type except Array?
If you can use C++11, creating your type traits; by example
#include <string>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename>
struct isArray : public std::false_type
{ };
template <typename T>
struct isArray<Array<T>> : public std::true_type
{ };
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return isArray<T>::value; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
If you can't use C++11 or newer but only C++98, you can simply write isArray as follows
template <typename>
struct isArray
{ static const bool value = false; };
template <typename T>
struct isArray< Array<T> >
{ static const bool value = true; };
and avoid the inclusion of type_traits
--- EDIT ---
Modified (transformed in constexpr) isArrayFunc(), as suggested by Kerrek SB (thanks!).
Below is a shorter version of the solution proposed by max66 that no longer uses struct isArray.
It works in C++98 and later revisions.
#include <string>
#include <vector>
#include <iostream>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return false; }
template <typename T>
constexpr bool isArrayFunc (Array<T> const &)
{ return true; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
in c++ you can use
if(typeid(obj1)==typeid(ob2))//or typeid(obj1)==classname
cout <<"obj1 is instance of yourclassname"
in your case you can check that with typeid(obj1)==std::array

Template specialization using another class that implicit-converts to it

I don't know if this is possible, but I would like to understand better how this works.
Can a class implict convertsion operation be used to match a template parameter?
This is what I want to do.
#include <iostream>
template<typename T>
struct Value {
};
template<>
struct Value<int> {
static void printValue(int v) {
std::cout << v << std::endl;
}
};
struct Class1 {
int value;
};
/*
template<>
struct Value<Class1*> {
static void printValue(Class1* v) {
std::cout << v->value << std::endl;
}
};
*/
template<typename X>
struct ClassContainer {
ClassContainer(X *c) : _c(c) {}
operator X*() { return _c; }
X *_c;
};
template<typename X>
struct Value<ClassContainer<X>> {
static void printValue(ClassContainer<X> v) {
std::cout << static_cast<X*>(v)->value << std::endl;
}
};
template<typename X>
void doPrintValue(X v)
{
Value<X>::printValue(v);
}
int main(int argc, char *argv[])
{
doPrintValue(10);
Class1 *c = new Class1{ 20 };
//doPrintValue(c); // error C2039: 'printValue': is not a member of 'Value<X>'
ClassContainer<Class1> cc(c);
doPrintValue(cc);
std::cout << "PRESS ANY KEY TO CONTINUE";
std::cin.ignore();
}
ClassContainer has an implict conversion to X*. Is it possible to match ClassContainer passing only X*?
If you want the template class for pointers to behave like the template class for something else, just inherit:
template<typename T>
struct Value<T*> : Value<ClassContainer<T>> {};
It will inherit the public printValue function, which accepts a parameter that can be constructed from T*, and everything will be implicitly converted as expected.
See it all live here.

Template Specilization with multiple template parameters in one function

I want template specilization with two parameters in one function. Here is a sample of code.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template <typename T> void Printer<T>::print()
{
std::cout << value << "\n";
}
template <> void Printer<std::string>::print()
{
std::cout << "\"" << value <<"\"\n";
}
template <> void Printer<const char *>::print()
{
std::cout << "\"" << value <<"\"\n";
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
}
Is there a way I can make the template speciazation for std::string and const char * in one function. I want this because they are doing the same thing.
You can use traits to add indirection on the specific behavior, based on type.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template<typename T>
struct PrinterTypeTraits {
static constexpr char* prefix = "";
static constexpr char* postfix = "";
};
template<>
struct PrinterTypeTraits<std::string> {
static constexpr char prefix = '\"';
static constexpr char postfix = '\"';
};
template<>
struct PrinterTypeTraits<const char*> : PrinterTypeTraits<std::string> {};
template <typename T> void Printer<T>::print()
{
using Traits = PrinterTypeTraits<T>;
std::cout << Traits::prefix << value << Traits::postfix << '\n';
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
return 0;
}