C++ Partially specializing parameter in fuction - c++

As a way of learning and understanding templates in C++, we have to solve a rather simple problem with templates. Currently my program is structured as followed (minus the unrelated methods):
"LFO.h"
enum Behaviors {LIFO, FIFO};
template<typename DataType, Behaviors Behavior, int MaxElems = 10>
class LFO {
public:
bool Palindrome(LFO& p);
}
"StringFIFO.h"
template<int MaxElems = 10>
class LFO<std::string, FIFO, MaxElems> {
public:
bool Palindrome(LFO& p) {
std::cout << "FIFO Palindrome." << std::endl;
return true;
}
}
"StringLIFO.h"
template<int MaxElems = 10>
class LFO<std::string, LIFO, MaxElems> {
public:
bool Palindrome(LFO& p) {
std::cout << "LIFO Palindrome." << std::endl;
return true;
}
}
The problem is.. When I attempt to access the Palindrome(LFO&) function:
auto myStringFIFO = new LFO<string, FIFO, 5>();
auto myStringLIFO = new LFO<string, LIFO, 5>();
myStringFIFO->Palindrome(*myStringLIFO);
It says that the Palindrome requires a LFO<std::string, 1, 5> which is a FIFO instead of LFO<std::string, 0, 5> which is the LIFO that I wish to pass into the method.
When I attempt to call the Palindrome(LFO&) method on my LIFO instead, the exact opposite happens. Somehow "LFO&" becomes specified according to which specialized class I call it from.
I'm quite stuck on how to fix this. I've attempted adding a template to the method in the base class, which fixes the error in my IDE, but throws an error that no definition for the method is found.
It's pretty hard to explain correctly as I'm not very familiar to templates.

Within a template specialization (primary or not), the name of the template is short hand for this particular instance of the template.
bool Palindrome(LFO& p) {
std::cout << "LIFO Palindrome." << std::endl;
return true;
}
so this LFO is this specific LFO specialization.
template<class T, SubB, int SubE>
bool Palindrome(LFO<T,SubB, SubE>& p) {
std::cout << "LIFO Palindrome." << std::endl;
return true;
}
this is a function that takes a templated type, behavior and max size.
template<SubB, int SubE>
bool Palindrome(LFO<std::string,SubB, SubE>& p) {
std::cout << "LIFO Palindrome." << std::endl;
return true;
}
this one doesn't template the type, but does template the behavior and max elements.

Related

Custom pair class with the operator[] syntax

I have this code
template<typename firstType,typename secondType>
struct bpair{
firstType first;
secondType second;
bpair(firstType firstNew,secondType secondNew) {
first = firstNew;
second = secondNew;
}
variant<firstType,secondType> operator[](size_t index) {
if(index == 0) {
return first;
}
return second;
}
};
bpair<string,int> hey = bpair(string("hi"),34);
cout << get<string>(hey[0]);
It is just a custom std::pair. Is there a way to load info from the pair using just the [] operator like this?
cout << hey[0];
A function can have only one return type. The return type cannot depend on a runtime parameter passed to the function.
Your cout << get<string>(hey[0]); selects at compile time that you want to retrieve the std::string member from the std::variant.
It is not (easily) possible to make this possible
cout << hey[0];
When hey[0] and hey[1] are supposed to call the same function.
You could let hey return some proxy type that when piped to std::cout selects the right member. Eventually, this would use again std::variant or similar under the hood (and require some boilerplate for not much gain).
For a solution that selects the member to be returned at compile time I repeat a solution suggested by Jarod42:
template <std::size_t I>
auto& operator[](std::integral_constant<std::size_t, I>) {
if constexpr {I == 0} { return first; }
else { return second; }
}
std::cout << hey[0_c] << " " << hey[1_c];
Note that hey[0_c] and hey[1_c] are calling two different instantiations of the template. Each with a different return type.

calling version of is_const<> but for variables instead of types, in one line

Hi I am learning c++ and I read about type traits such as is_const.
is_const can be called in one line like,
cout << is_const<double>::value << endl;
I made my own version of is_const but to test if a variable is const, and it can be used like this,
#include<iostream>
using namespace std;
template<typename T>
struct check_const {
check_const(const T *x): val(std::true_type{})
{ }
check_const(T *x) : val(std::false_type{})
{ }
bool val;
};
int main()
{
const double pi= 3.14;
check_const<double> r(&pi);
cout << r.val << endl; // returns 1
double x= 2.7;
check_const<double> s(&x);
cout << s.val << endl; // returns 0
return(0);
}
I would like to call check_const in one line as well, but the compiler keeps giving me errors like
"typename not allowed"
when I try calling it like
cout << check_const<double> t(&pi)::val << endl;
How can I change check_const, so it can be called in one line?
You are just using a slightly wrong syntax here:
cout << check_const<double> t(&pi)::val << endl;
Instead use
cout << check_const<double>(&pi).val << endl;
check_const<double> t(&pi) is the syntax for the definition of a named variable, but you cannot have declarations/definitions inside an expression.
check_const<double>(&pi) is the syntax to create an unnamed temporary, which can be done in expressions.
Then you need . instead of ::, because val is a non-static member of check_const.
Starting with C++17 you could also write:
cout << check_const(&pi).val << endl;
and have the template argument be deduced for you.
All of this can be simplified though, as you aren't really using the class. You can just use the constructors as free functions:
template<typename T>
constexpr bool check_const(const T *x) noexcept { return true; }
template<typename T>
constexpr bool check_const(T *x) noexcept { return false; }
(The constexpr makes it possible to use the functions in constant expressions, but is otherwise not required. Similarly noexcept is just an indicator that the function doesn't throw exceptions, but is otherwise not required.)
This can be used more easily as
cout << check_const(&pi) << endl;
Also, instead of pointers, use references:
template<typename T>
constexpr bool check_const(const T &x) noexcept { return true; }
template<typename T>
constexpr bool check_const(T &x) noexcept { return false; }
and you can write
cout << check_const(pi) << endl;

how to return a reference to a default value of a non-type template argument

I have done a lot of research on this but I wasn't able to find a design pattern addressing the problem. This is a minimal description of what I'm trying to perform.
#include <iostream>
using namespace std;
template <class T, T default_value=T{}>
class A{
private:
T inclassValue;
public:
A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_value;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
/*
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
*/
return 0;
}
The code will compile, link and output as expected
a[0]=0
a[1]=4
The compiler complains though and issues a warning for the line of code where default_value is used
return default_value;//Returning reference to local temporary object
which makes some sense. Uncommenting the last part in main and compiling, the compiler issue this time an error while building the template
template <class T, const T default_value= T{}>//A non-type template parameter cannot have type 'two_int'
while what I ideally hope for is
b[0]=0,0
b[1]=3,5
I was able to come up with a solution by adding an extra helper class, that will provide the default_value of T (as a static member), to the template arguments. I'm not convinced by the robustness of my trick and I was wondering if there exists a design pattern addressing this. The warning for types and the error for non-types. Also, I shall add that my primary goal is to be able to provide default_value at will (6 for int for example instead of 0).
Thanks
Not exactly sure what you're looking for, but perhaps a static helper finishing for creating a static default T could be useful:
template <typename T>
static const T& default_value() {
static const T* t = new T{};
return *t;
}
Note this will construct T at most once even across threads (in c++11), but still never destruct T. Since it's static, it's likely the lack of destruction is acceptable, but this of course depends on T.
Here is one version that forwards arguments to the constructor of a default_value stored as constexpr. You are quite limited here as to what is valid to pass as arguments (not sure exactly how limited) so it will depend on your use-case.
#include <iostream>
using namespace std;
template <class T, auto... Args>
class A{
private:
T inclassValue;
constexpr static T default_val = T{Args...}; // Changed to curly brackets here
public:
constexpr A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_val;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
return 0;
}

class parametrized with classes and confusion with helper functions

I'm learning some new concepts about c++ and I'm playing with them.
I wrote some piece of code that really confuses me in terms of how it works.
#include <iostream>
class aid {
public:
using aid_t = std::string;
void setaid(const std::string& s) {
aid_ = s;
}
const aid_t& getaid() const {
return aid_;
}
private:
aid_t aid_;
};
class c {
public:
using c_t = std::string;
void setc(const aid::aid_t& aid_val) {
if (aid_val.size() < 4)
c_ = "yeah";
else
c_ = aid_val + aid_val;
}
const c_t& getc() {
return c_;
}
private:
c_t c_;
};
template<typename ...Columns>
class table : public Columns... {
};
template <typename... Columns>
void f(table<Columns...>& t) {
t.setaid("second");
std::cout << t.getaid() << "\n";
}
void f2(table<aid>& t) {
t.setaid("third");
std::cout << t.getaid() << "\n";
}
int main() {
table<aid, c> tb;
tb.setaid("first");
std::cout << tb.getaid() << " " << "\n";
// f<c>(tb); // (1) doesnt compile, that seem obvious
f<aid>(tb); // (2) works?
f(tb); // (3) works too -- template parameter deduction
// f2(tb); // (4) doesnt work? worked with (2)...
}
The idea here is simple, I have some table with columns. And then I would like to create some functions that require only some set of columns and doesn't care if passed argument has some extra columns.
My confusion is mostly about points (2) and (4) in code... My intuition says it should be the same, why it isn't and (2) compiles and (4) doesn't? Is there any major topic I'm missing and should read up?
Is there a way to achieve this particular functionality?
In the second case, the compiler still deduces the rest of the template parameter pack, so that you get table<aid, c> & as the function parameter. This is different from (4) (table<aid> &).
[temp.arg.explicit]/9:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.

overloading template function

Currently, I encounter some difficulty in overloading a certain function. here's my code:
template<typename Value>
bool process(Value thisValue)
{
return processAccordingToTheType(thisValue);
}
So, there are two overloaded function of processAccordingToTheType:
bool processAccordingToTheType(int thisValue){}
bool processAccordingToTheType(string thisValue){}
when I try to compile it, it said:
error C2665: 'processAccordingToTheType' : none of the 2 overloads could convert all the argument types
what do I need to do?
Update:
int main()
{
int i = 1;
process <int> (i);
}
From your sample code I understand you need two things to be done:
Call a type specific process function
Restrict these calls to string and int types
Wrapping the processAccordingToType function inside process<T> is completely redundant: process<T> actually means 'process according to type'. The keyword here is 'template specialization'. You need to specialize your 'process according to type' method for int and string.
You can do this as below:
#include <iostream>
using namespace std;
template<typename T>
bool process(T t)
{
// call a Compile-Time Assertion
cout << "I don't want this to be called." << endl;
}
template <>
bool process<int>(int i)
{
cout << "process(int) called." << endl;
}
template <>
bool process<string>(string s)
{
cout << "process(string) called." << endl;
}
int main()
{
process(1);
process(string("s"));
process(1.0d);
}
Output:
process(int) called.
process(string) called.
I don't want this to be called.
Ideally, you want to prevent the users of your API calling process with other types. Allowing them to call and handling this at runtime (like it's done in my example) is not acceptable. You achieve this with Compile-Time Assertions. Read "Modern C++ Designs" by Andrei Alexandrescu for ways of doing that.
Look into template specialization. Does what you're looking for without deferring to another function based on type.
http://www.cprogramming.com/tutorial/template_specialization.html
You can overload function templates with either a non-template function or another template function. Make sure that whatever you do, you test incrementally as template errors are notoriously hard to understand.
http://www.cplusplus.com/doc/tutorial/templates/
#include <iostream>
using namespace std;
template <typename Value>
bool processAccordingToTheType( Value thisValue ){
cout << "Generic Type" << endl;
return false;
}
bool processAccordingToTheType(int thisValue){
cout << "int type" << endl;
return true;
}
template <typename Value>
bool process( Value thisValue ){
return processAccordingToTheType(thisValue);
}
int main( int argc, char* argv[] ){
cout << process( 1 ) << endl;
cout << process( "Hello" ) << endl;
return 0;
}