The title is pretty much self explanatory. Here is my situation:
#include <type_traits>
class C1{
enum{
c1 = 3
}
}
class C2{
enum{
c2 = 10
}
}
template<class C>
class C3{
void do_this();
void do_that();
void foo(){
if constexpr(std::is_enum<C::c1>::value){
do_this();
}
if constexpr(std::is_enum<C::c2>::value){
do_that();
}
}
}
If I'd try to compile this I'd get the error
error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c1’
error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c2’
So hence my question: is it possible to use std::is_enum with unnamed enums?
C++11 using SFINAE
You can use decltype to get the type associated with c1 and c2 and then use SFINAE as shown below . C++11 Demo:
struct C1{
enum{
c1 = 3
};
};
struct C2{
enum{
c2 = 10
};
};
template<class C>
class C3{
void do_this(){std::cout << "do this called" << std::endl;}
void do_that(){std::cout << "do that called " << std::endl;}
public:
//overload for calling do_this
template<typename T = C,typename std::enable_if<std::is_same<T, C1>::value, bool>::type = std::is_enum<decltype(T::c1)>::value >void foo()
{
do_this();
}
//overload for calling do_that
template<typename T = C,typename std::enable_if<std::is_same<T, C2>::value, bool>::type = std::is_enum<decltype(T::c2)>::value >void foo()
{
do_that();
}
//overload when none of the conditions are satisfied
template<typename... T>
void foo(T...)
{
std::cout <<"ellipsis called " << std::endl;
}
};
int main()
{
C3<C1> c1;
c1.foo(); //calls do_this() using #1
C3<C2> c2;
c2.foo(); //calls do_that() using #2
C3<int> c3;
c3.foo(); //calls the ellipsis version
}
See also C++ 17 demo version that uses std::enable_if_t and std::is_same_v and std::is_enum_v.
C++20 using concept
struct C1{
enum{
c1 = 3
};
};
template<typename T>
concept enumC1 = std::is_same_v<T, C1>;
struct C2{
enum{
c2 = 10
};
};
template<typename T>
concept enumC2 = std::is_same_v<T, C2>;
template<class C>
class C3{
void do_this(){std::cout << "do this called" << std::endl;}
void do_that(){std::cout << "do that called " << std::endl;}
public:
//overload when none of the conditions are satisfied
template<typename T = C>
void foo()
{
std::cout <<"general called " << std::endl;
}
//overload for calling do_this
template<enumC1 T = C>void foo()
{
do_this();
}
//overload for calling do_that
template<enumC2 T = C>void foo()
{
do_that();
}
};
int main()
{
C3<C1> c1;
c1.foo(); //calls do_this()
C3<C2> c2;
c2.foo(); //calls do_that()
C3<int> c3;
c3.foo(); //calls the general version
}
C++ 20 demo
You should probably name the them both the same thing so the template works with both of them:
#include <cstdio>
#include <type_traits>
struct C1 {
enum { c = 3 };
};
struct C2 {
static constexpr int c = 10;
};
template <class C>
void foo() {
if constexpr (std::is_enum_v<decltype(C::c)>) {
std::puts("::c is an enum");
} else {
std::puts("::c is not an enum");
}
}
int main() {
foo<C1>();
foo<C2>();
}
Related
Is the following program compliant C++11? If so, do you know of a specific MSVC bug that triggers it? and/or a possible work-around?
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
template <typename T>
void foo(T, decltype(aaa)) { std::cout << "a"; }
template <typename T>
void foo(T, decltype(bbb)) { std::cout << "b"; }
// ^ C2995 'void foo(T,unknown-type)': function template has already been defined
int main()
{
foo(0, aaa);
foo(0, bbb);
}
If the actual types are substituted for decltype then it works, but in practice these types are too complicated to reproduce and I'd prefer not to have aliases for them.
Works for me (VS 2015 / v140) with the following minor modification:
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
using A_type = decltype(aaa);
using B_type = decltype(bbb);
template <typename T>
void foo(T, A_type) { std::cout << "a"; }
template <typename T>
void foo(T, B_type) { std::cout << "b"; }
int main()
{
foo(0, aaa);
foo(0, bbb);
}
But this variant yields the same error (not sure what to make of it):
template <typename T>
struct TypeWrapper {
using type = T;
};
template <typename T>
void foo(T, typename TypeWrapper<decltype(aaa)>::type) { std::cout << "a"; }
template <typename T>
void foo(T, typename TypeWrapper<decltype(bbb)>::type) { std::cout << "b"; }
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.
I have a class which I intend to use with either the type float or double. As far as I am aware, there is no way to restrict template options, so perhaps I might be doing something dangerous here?
template<class T>
class A
{
A(T arg) { _data = arg; }
T _data;
}
typedef A<float> A_f;
typedef A<double> A_d;
How can I do the following?
int main()
{
A_f f(3.1415);
A_d d(3.1415);
f = (A_f)d;
}
IE: Cast the class containing data of type double to the class containing data of type float.
Edit: This doesn't seem to be going anywhere, so I tried playing around with this, but obviously I have no idea what to do here so it doesn't compile...
template<class T>
class A
{
friend // Intention is for T to be double here
A<float> operator A<float>(const A<T> input);
}
A<float> operator A<float>(const A<double> input)
{
return A<float>(input._data);
}
Maybe this helps explain what I want to achieve?
Second Edit for Adam:
return A<float>((float)input._data);
Is this better?
You could use std::enable_if to only allow certain types :
#include <type_traits>
using namespace std;
// Our catch-all is not defined, so will not compile
// Could also be made to print a nice error message
template<typename T, typename Sfinae = void> class A;
// Ok if T is float or double
template<typename T>
class A<T, typename std::enable_if<std::is_same<T, float>::value
|| std::is_same<T, double>::value>::type>
{
// Your class here
};
int main()
{
A<int> a; // FAILS
A<float> b; // Ok
A<double> c; // Ok
return 0;
}
Then you just need to define a conversion operator in your class for the cast to work.
Do not cast, but provide one (and only one) implicit conversion constructor or conversion operator. In your case it might be as trivial as operator T () const { return _data; }
I'll second the arguments that you should not cast like that, but if you insist, add a templated copy constructor:
template<class T>
class A
{
public: // add this
A(T arg) { _data = arg; }
template <class U> // add this
A(A<U> arg) { _data = arg._data; } // add this
T _data;
}
This will then allow conversions from A<U> to A<T> as long as U is implicitly convertible to T.
There is an option to customize a class based on the type you provide it. The technique is called 'template specialization'
#include <iostream>
using namespace std;
template <typename T>
class A {
public:
void print_my_type() {
cout << "Generic template instance" << endl;
}
explicit operator A<int>() const {
cout << "Casting to int" << endl;
return A<int>();
}
};
template <>
class A<int> {
public:
void print_my_type() {
cout << "Class templated with an int" << endl;
}
explicit operator A<double>() const {
cout << "Casting to double" << endl;
return A<double>();
}
};
int main() {
A<double> a;
A<int> b;
a.print_my_type();
b.print_my_type();
a = static_cast<A<double>>(b);
return 0;
}
You should not cast objects like that. If you intend to have an object that you want to cast to another. You should provide it an operator A() method so it can handle conversions gracefully
Example with template conversion operator + static_assert for type verify:
http://coliru.stacked-crooked.com/a/6b01010ea5f02aee
#include <vector>
#include <iostream>
template < typename T > class TD; // type visualiser
template<class T>
class A
{
public:
A(T arg) { _data = arg; }
template<typename D>
operator A<D>() {
static_assert(std::is_same<D, float>::value || std::is_same<D, double>::value, "double/floats allowed only");
//TD<D>(); // D is float here
return static_cast<D>(_data);
}
T _data;
};
typedef A<float> A_f;
typedef A<double> A_d;
typedef A<int> A_i;
int main() {
A_f f(3.14151);
A_d d(3.14152);
std::cout << f._data << std::endl;
std::cout << d._data << std::endl;
f = (A_f)d;
//f = (A_i)d; // static assertion here
std::cout << f._data << std::endl;
return 0;
}
[edit]
template<class T>
class A
{
public:
A(T arg) { _data = arg; }
template<typename D>
operator A<D>() {
static_assert(std::is_same<D, float>::value || std::is_same<D, double>::value, "double/floats allowed only");
//TD<D>(); // D is float here
return A<D>(static_cast<D>(_data));
}
T _data;
};
The following code doesn't compile:
#include <boost/variant.hpp>
class A {};
class B {};
class C {};
class D {};
using v1 = boost::variant<A, B>;
using v2 = boost::variant<C, D>;
int f(v1 const&) {
return 0;
}
int f(v2 const&) {
return 1;
}
int main() {
return f(A{});
}
both gcc and clang complains with:
test1.cpp: In function ‘int main()’:
test1.cpp:18:17: error: call of overloaded ‘f(A)’ is ambiguous
return f(A{});
^
test1.cpp:18:17: note: candidates are:
test1.cpp:11:5: note: int f(const v1&)
int f(v1 const&) {
^
test1.cpp:14:5: note: int f(const v2&)
int f(v2 const&) {
Given that is not possible to construct a v2 object from an A instance why the compiler gives the same priority to both functions during the overload resolution?
The problem is the constructor
template<typename T>
variant(const T&)
of boost::variant. The code below reproduces the problem without all the magic:
struct C {};
struct A {
A(const C&) {}
template<typename T>
A(const T&) {}
};
struct B {
template<typename T>
B(const T&) {}
};
int f(const A&) {
return 0;
}
int f(const B&) {
return 1;
}
int main() {
return f(C{});
}
I think the variant constructor should only be enabled if the
argument is actually convertible to the arguments, you might want to
raise this as a bug.
A pragmatic approach, short of fixing the conversion with explicit conversion with proper SFINAE (I don't think it can be done elegantly outside the Boost Variant library), could be this:
See it Live On Coliru
#include <boost/variant.hpp>
class A {};
class B {};
class C {};
class D {};
using v1 = boost::variant<A, B>;
using v2 = boost::variant<C, D>;
namespace detail {
struct F : boost::static_visitor<int> {
template <typename... T>
int operator()(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}
int operator()(A) const { return 0; }
int operator()(B) const { return 0; }
int operator()(C) const { return 1; }
int operator()(D) const { return 1; }
} _f;
}
template <typename T>
int f(T const& t) {
return detail::F()(t);
}
int main() {
std::cout << f(A{}) << "\n";
std::cout << f(B{}) << "\n";
std::cout << f(C{}) << "\n";
std::cout << f(D{}) << "\n";
std::cout << f(v1{}) << "\n";
std::cout << f(v2{}) << "\n";
}
Prints
0
0
1
1
0
1
The assumption is that f(T) always returns the same value for the same T even if it is the member of more than one variant
Can I overload a template class function in a class that extends its specialization?
I have the following piece of code (I've tried to simplify it to the bare minimum):
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return foo(i);
}
};
class B : public A<Y, X> {
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
However the compiler produces the following error:
hello.cc: In member function ‘unsigned int A<T, U>::bar(T) [with T = Y, U = X]’:
hello.cc:47: instantiated from here
hello.cc:30: error: no matching function for call to ‘A<Y, X>::foo(Y&)’
hello.cc:24: note: candidates are: unsigned int A<T, U>::foo(U) [with T = Y, U = X]
Basically I would like to overload the function A::foo() in its derived class B.
Apparently what you're asking is called "static polymorphism" and it's achieved by the means of "curiously recurring template pattern":
template <typename Derived, typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return static_cast<Derived*>(this)->foo(i);
}
};
class B : public A<B, Y, X> {
public:
// Uncomment this line if you really want to overload foo
// instead of overriding. It's optional in this specific case.
//using A::foo;
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
I don't think the overloads in derived classes cannot be used from the base class where they are to be called from.
What you can do, is to extract the foo method, so you can specialize it for B.
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
struct Foo
{
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
};
template <typename T, typename U>
class A : public Foo<T, U> {
public:
unsigned bar(T i) {
return this->foo(i);
}
};
template <>
struct Foo<Y, X>
{
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
class B : public A<Y, X> {
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
Edit: My first answer was incorrect.
When you instantiate A with classes Y and X the call of foo(T) generates an error because there no proper overloaded method defined in A. It suffices to declare a pure virtual method of foo(T) in A and implement this method in B.
template <typename T, typename U>
class A {
public:
virtual unsigned foo(T i) = 0;
unsigned foo(U i) { /* as above */ }
unsigned bar(T i) {
return foo(i); // calls abstract foo(T)
}
};
/* B is left untouched */
Compiling this generates this output:
B
Hello: 2