Suppose I have some structs and each of them holds one enum as a member.
I want to call a method of a struct but depending on a struct's member, like in the code example:
#include <iostream>
#include <string>
#include <type_traits>
enum class Type{
lowercase = 0,
uppercase
};
struct Low{
static constexpr Type cp = Type::lowercase;
};
struct Up{
static constexpr Type cp = Type::uppercase;
};
template<typename Case, typename=void>
struct Printer
{
void print_g(const std::string& s){
std::cout << "just s: " << s << std::endl;
}
};
template<typename X>
struct Printer<X, std::enable_if_t<X::cp == Type::lowercase, void>>
{
void print_g(const std::string& s){
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<typename X>
struct Printer <X, std::enable_if_t<X::cp == Type::uppercase, void>>
{
void print_g(const std::string& s){
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};
int main()
{
Printer<Low> pl;
pl.print_g("hello1");
Printer<Up> p2;
p2.print_g("hello2");
}
But this solution doesn't look quite elegant to me.
Especially the part typname=void in the first template.
Only then code compiles. Why is that the case?
And is there any better (more elegant) solution for this template specialization?
In C++17, you can use if constexpr:
template <typename X>
struct Printer
{
void print_g(const std::string& s)
{
if constexpr(X::cp == Type::lowercase)
{
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
else if constexpr(X::cp == Type::uppercase)
{
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
else
{
std::cout << "just s: " << s << std::endl;
}
}
};
If you do not have access to C++17, consider these options:
Use a regular if...else statement. There's no code that needs to be conditionally compiled in your example.
Implement static_if in C++14. Here's a talk I gave that explains how to do it: Implementing static control flow in C++14
You can fully specialize Printer for Low and Up.
template<class Case>
struct Printer
{
void print_g(const std::string& s) {
std::cout << "just s: " << s << std::endl;
}
};
template<>
struct Printer<Low>
{
void print_g(const std::string& s) {
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<>
struct Printer<Up>
{
void print_g(const std::string& s) {
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};
Notice that the enum does not come into play at all. If you need to specialize for the enum, you can do that too.
template<Type Case>
struct PrinterHelper
{
void print_g(const std::string& s) {
std::cout << "just s: " << s << std::endl;
}
};
template<>
struct PrinterHelper<Type::lowercase>
{
void print_g(const std::string& s) {
std::cout << "lowercase " << std::nouppercase << s << std::endl;
}
};
template<>
struct PrinterHelper<Type::uppercase>
{
void print_g(const std::string& s) {
std::cout << "uppercase " << std::uppercase << s << std::endl;
}
};
template<class Case>
using Printer = PrinterHelper<Case::cp>;
I would likely just go with:
enum struct Casing
{
Lower,
Upper
};
template<Casing>
struct printer;
template<>
struct printer<Casing::Lower>
{
...
};
template<>
struct printer<Casing::Upper>
{
...
};
Related
I want to know if it's possible to have the same function but for different type like in c++ for Typescript ?
#include <iostream>
template <typename T>
void print(double x)
{
std::cout << "IS DOUBLE: " << x << std::endl;
}
template <typename T>
void print(int x)
{
std::cout << "IS INT: " << x << std::endl;
}
template <typename T>
void print(std::string x)
{
std::cout << "IS STRING: " << x << std::endl;
}
int main()
{
print<int>(2);
print<double>(8.0);
print<std::string>("HA");
return 0;
}
There is the output
IS INT: 2
IS DOUBLE: 8
IS STRING: HA
This question already has answers here:
What is object slicing?
(18 answers)
Closed 1 year ago.
I am building up a CRTP interface and noticed some undefined behavior. So, I built up some sample code to narrow down the problem.
#include <iostream>
template <typename T>
class Base {
public:
int a() const { return static_cast<T const&>(*this).a_IMPL(); }
int b() const { return static_cast<T const&>(*this).b_IMPL(); }
int c() const { return static_cast<T const&>(*this).c_IMPL(); }
};
class A : public Base<A> {
public:
A(int a, int b, int c) : _a(a), _b(b), _c(c) {}
int a_IMPL() const { return _a; }
int b_IMPL() const { return _b; }
int c_IMPL() const { return _c; }
private:
int _a;
int _b;
int _c;
};
template <typename T>
void foo(const T& v) {
std::cout << "foo()" << std::endl;
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
std::cout << "b() = " << static_cast<Base<T>>(v).b() << std::endl;
std::cout << "c() = " << static_cast<Base<T>>(v).c() << std::endl;
}
int main() {
A v(10, 20, 30);
std::cout << "a() = " << v.a() << std::endl;
std::cout << "b() = " << v.b() << std::endl;
std::cout << "c() = " << v.c() << std::endl;
foo(v);
return 0;
}
The output of this code is:
a() = 10
b() = 20
c() = 30
foo()
a() = 134217855
b() = 0
c() = -917692416
It appears that there is some problem when casting the child class, which implements the CRTP "interface", to the interface itself. This doesn't make sense to me because the class A plainly inherits from Base so, shouldn't I be able to cast an instance of A into Base?
Thanks!
You copy and slice when you cast to Base<T>.
Cast to a const Base<T>& instead:
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
std::cout << "b() = " << static_cast<const Base<T>&>(v).b() << std::endl;
std::cout << "c() = " << static_cast<const Base<T>&>(v).c() << std::endl;
It turns out I was casting incorrectly to a value rather than a reference
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
should become
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
Why b.isEm() prints different things on different lines when I have not changed anything after the last call of b.isEm()?
#include <iostream>
#include <string>
template <class T>
class Box
{
bool m_i;
T m_c;
public:
bool isEm() const;
void put(const T& c);
T get();
};
template <class T>
bool Box<T>::isEm() const
{
return m_i;
}
template <class T>
void Box<T>::put(const T& c)
{
m_i = false;
m_c = c;
}
template <class T>
T Box<T>::get()
{
m_i = true;
return T();
}
int main()
{
Box<int> b;
b.put(10);
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
}
The order of evaluation of function arguments in C++ is unspecified.
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Since b.get() has side effects, I suggest you call it separately...
auto g = b.get();
std::cout << g << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Note: std::cout << .... << ... << is a function call with the arguments ...
I am trying to understand template specialization in C++. I have read other forums, but cannot get it working in practice. I am trying to learn with a very simple example which I will explain.
What I would like to accomplish: I want foo to exhibit different behaviors based on the type. The code below does not work, but I have commented the behavior I would like to see. Could someone please fill in the lines that I commented. Please let me know if anything is unclear.
#include <iostream>
#include <string>
template <typename T>
class my_template
{
public:
foo() {return 0} // default behavior if there does not exist foo() function for the specified type
};
template <>
class my_template<int>
{
public:
// implement foo function: should return -1 if the type = int
};
template <>
class my_template<long>
{
public:
// implement foo function: should return 100 if the type = long
};
int main()
{
my_template<int> x;
my_template<long> y;
my_template<double> z;
std::cout << x.foo() << "\n"; // print -1
std::cout << y.foo() << "\n"; // print 100
std::cout << z.foo() << "\n"; // print 0
return 0;
}
Just to show you a few different approaches.
If you use a metafunction approach, then nothing will ever be done at run-time (guaranteed):
template<typename>
struct my_template{
enum { value = 0 };
};
template<>
struct my_template<int>{
enum { value = -1 };
};
template<>
struct my_template<long>{
enum { value = 100 };
};
int main(){
std::cout << "float: " << my_template<float>::value << '\n';
std::cout << "int: " << my_template<int>::value << '\n';
std::cout << "long: " << my_template<long>::value << '\n';
}
Or you could use a template variable ( C++14 ):
template<typename>
constexpr int my_value = 0;
template<>
constexpr int my_value<int> = -1;
template<>
constexpr int my_value<long> = 100;
int main(){
std::cout << "float: " << my_value<float> << '\n';
std::cout << "int: " << my_value<int> << '\n';
std::cout << "long: " << my_value<long> << '\n';
}
Or use a template function:
template<typename T>
int func_impl(T){ return 0; }
int func_impl(int){ return -1; }
int func_impl(long){ return 100; }
template<typename T>
int func(){
return func_impl(T(0));
}
int main(){
std::cout << "float: " << func<float>() << '\n';
std::cout << "int: " << func<int>() << '\n';
std::cout << "long: " << func<long>() << '\n';
}
template <typename T>
class my_template
{
public:
int foo() {return 0;} // default behavior
};
template <>
class my_template<int>
{
public:
int foo() {return -1;}
};
Is that enough?
I'm trying to build a utility that involves inheriting from the same base multiple times, which I'm doing by templating on an integer to make the bases distinct. Unfortunately I've found myself writing something like the following:
template<size_t I>
struct X {};
template<size_t Len>
struct Y { static_assert(false, "exceeded max length"); };
template<>
struct Y<0> {};
template<>
struct Y<1> : X<0> {};
template<>
struct Y<2> : X<0>, X<1> {};
template<>
struct Y<3> : X<0>, X<1>, X<2> {};
Although this used to be a very common pattern in the old days of nasty C++, I can't help but feel better can be done in C++11, although the details elude me.
Can this be done succintly, for arbitrary Len?
(any ideas for a better title are also appreciated)
If the hierarchy does not have to be flat then:
#include <iostream>
#include <iomanip>
#include <type_traits>
template<size_t N> struct X : X<N - 1> {};
template<> struct X<0> {};
template<size_t N>
struct Y : X<N - 1> {};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_base_of<X<0>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<1>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<2>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<3>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<4>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<5>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<6>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<7>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<8>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<9>, Y<10>>::value << "\n"; // true
std::cout << std::is_base_of<X<10>, Y<10>>::value << "\n"; // false
}
See online demo at http://ideone.com/wsgAhQ .
What's wrong with a bit of recursive inheritance ?
template<size_t I>
struct X {};
template<size_t I>
struct InheritFromX : X<I> , InheritFromX <I-1> {};
template<>
struct InheritFromX<0> {};
struct Mystruct : InheritFromX<3> { } // inherits X 3 times