C++ Variadic Template Remove Function Logic - c++

I've been able to progress further with my variadic template from my previous question. I've now got a new question. In this code example:
#include <iostream>
#include <cstddef>
constexpr std::uint32_t Flag0 = 0x0001;
constexpr std::uint32_t Flag1 = 0x0002;
constexpr std::uint32_t Flag2 = 0x0004;
constexpr std::uint32_t FlagAll = 0xFFFF;
template<std::uint32_t...Cs>
struct flags_tag {constexpr flags_tag(){}; };
template<std::uint32_t...Cs>
struct make_flags{ using type=flags_tag<Cs...>; };
template<std::uint32_t...Cs>
using make_flags_t=typename make_flags<Cs...>::type;
template<std::uint32_t value>
class pValue_t
{
template<std::uint32_t StateMask, class flags>
friend class Compound;
};
template<> class pValue_t<Flag0>
{
public:
pValue_t() :
m_pValue0(reinterpret_cast<void*>(0xFFFFFFFF))
{}
protected:
void* m_pValue0;
};
template<> class pValue_t<Flag1>
{
public:
pValue_t() :
m_pValue1(reinterpret_cast<void*>(0xDEADBEEF))
{}
protected:
void* m_pValue1;
};
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
protected:
void* m_pValue2;
};
template<std::uint32_t StateMask, class flags>
class Compound;
template<std::uint32_t StateMask, std::uint32_t...Cs>
class Compound< StateMask, flags_tag<Cs...> >:
public pValue_t<Cs>...
{
public:
void print()
{
if (IsStateValid(Flag0))
{
std::cout << this->m_pValue0 << '\n';
}
if ((StateMask & Flag1) == Flag1)
{
std::cout << this->m_pValue1 << '\n';
}
// *** THIS IS THE PROBLEM STATEMENT ***
if (IsStateValid(Flag2))
{
std::cout << this->m_pValue2 << '\n';
}
}
static bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
uint32_t m_stateMask;
};
using my_type = Compound< Flag0 | Flag1, make_flags_t<Flag0, Flag1>>;
int main() {
my_type test;
test.print();
}
the print function contains a reference to m_pValue2, which is valid when the StateMask contains Flag2.
Now, the compiler is warning that it cannot find m_pValue2. I would like for the compiler to remove the chunk of code that references m_pValue2 when the StateMask (known at compile time) does not contain Flag2 (when IsStateValid() is false).
The exact error is as follows:
main.cpp: In instantiation of 'void Compound<StateMask, flags_tag<Cs ...> >::print() [with unsigned int StateMask = 3u; unsigned int ...Cs = {1u, 2u}]':
main.cpp:95:18: required from here
main.cpp:80:27: error: 'class Compound<3u, flags_tag<1u, 2u> >' has no member named 'm_pValue2'
std::cout << this->m_pValue2 << '\n';
I'm hoping this is possible. In other template programming, I've used IsStateValid() to compile out code segments that don't match the StateMask. I've never tried to compile away a possibly missing member variable, however.
Does anyone have any ideas?

Why it doesn't work
All branches in a function template will be compiled regardless of type. It doesn't matter that IsStateValid(Flag2) would be false at compile time, the body of that if must be valid code. As there is no this->m_pValue2 in that case, this is a hard error.
What can you do to fix it
You need to forward each print flag function to a function template that will either print the value (if it exists) or do nothing (if it doesn't). We can use function overloading to help here, and ensure that the entire function will not be instantiated if there is no such flag. For example:
void print()
{
printImpl<Flag0>();
printImpl<Flag1>();
printImpl<Flag2>();
}
template <uint32_t F>
void printImpl() {
printImpl<F>(std::is_base_of<pValue_t<F>, Compound>{});
}
template <uint32_t F>
void printImpl(std::true_type ) {
// we DO have this flag
pValue_t<F>::print();
}
template <uint32_t F>
void printImpl(std::false_type ) {
// we do NOT have this flag
// so do nothing
}
All you need to do at this point is add the appropriate print()s. e.g.:
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
void print() {
std::cout << m_pValue2 << '\n';
}
protected:
void* m_pValue2;
};

I got this to work (working example), but it seems very hacky. It shows that it's possible - hopefully a more experienced person than I can clean it up.
The idea is to make IsStataValid a constexpr and separate the code in question out into another function, which has two variants. The variant that gets instantiated depends on the compile-time flag:
static constexpr bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
template <typename A = void,
typename T = typename std::enable_if<IsStateValid(Flag2), A>::type>
void blub(int x=0) {
std::cout << this->m_pValue2 << '\n';
}
template <typename A = void,
typename T = typename std::enable_if<!IsStateValid(Flag2), A>::type>
void blub(long x=0) {
}
Then instead of the if statement in print() you call the helper function:
blub();
typename A is a dummy parameter to make the enable_if dependent on a template parameter so SFINAE can kick in. The blubs take a first parameter of a different type so the compiler doesn't complain about it not being able to be overloaded.

Related

When overloading a function with multiple inheritance, GCC says calling it is ambiguous, but Clang and MSVC do not

I am using this variant library: https://github.com/cbeck88/strict-variant. It provides a class similar to std::variant and boost::variant. Given this struct:
struct S
{
explicit S(double) {}
};
I want to do this:
strict_variant::variant<double, S> v = 2.0;
This works with Clang 5.0.1 and MSVC 19.12.25831.00, but fails to compile with GCC 7.2.1.
I looked at the library's code and reduced the problem to this:
#include <iostream>
struct S
{
constexpr S() {}
constexpr explicit S(double) {}
};
template<unsigned i> struct init_helper;
template<> struct init_helper<0> { using type = double; };
template<> struct init_helper<1> { using type = S; };
template<unsigned i>
struct initializer_leaf
{
using target_type = typename init_helper<i>::type;
constexpr unsigned operator()(target_type) const
{
return i;
}
};
struct initializer : initializer_leaf<0>, initializer_leaf<1>
{
};
int main()
{
std::cout << initializer()(double{}) << " = double" << '\n';
std::cout << initializer()(S{}) << " = S" << '\n';
return 0;
}
with the output being
0 = double
1 = S
GCC says:
strict_variant_test.cpp: In function ‘int main()’:
strict_variant_test.cpp:29:37: error: request for member ‘operator()’ is ambiguous
std::cout << initializer()(double{}) << " = double" << '\n';
^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
constexpr unsigned operator()(target_type) const
^~~~~~~~
strict_variant_test.cpp:17:21: note: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]
strict_variant_test.cpp:30:32: error: request for member ‘operator()’ is ambiguous
std::cout << initializer()(S{}) << " = S" << '\n';
^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
constexpr unsigned operator()(target_type) const
^~~~~~~~
strict_variant_test.cpp:17:21: note: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]
But, it works with GCC (and still Clang and MSVC) when I change the definition of initializer to this:
struct initializer
{
constexpr unsigned operator()(double) const
{
return 0;
}
constexpr unsigned operator()(S) const
{
return 1;
}
};
My understanding of C++ says that this is equivalent, so I assume that this is a bug in GCC, but I have often run into problems where the standard says surprising things and my assumption is wrong. So, my question is: whose fault is this? Does GCC have a bug, do Clang and MSVC have a bug, or is the interpretation of the code undefined/unspecified such that all compilers are right? If the code is wrong, how can it be fixed?
This is actually a clang bug.
The rule of thumb is that the names in different scopes don't overload. Here's a reduced example:
template <typename T>
class Base {
public:
void foo(T ) { }
};
template <typename... Ts>
struct Derived: Base<Ts>...
{};
int main()
{
Derived<int, double>().foo(0); // error
}
This should be an error because the class member lookup rules state that basically only one base class can contain a given name. If more than one base class has the same name, lookup is ambiguous. The resolution here is to bring both base class names into the derived class with a using-declaration. In C++17, that using declaration can be a pack expansion, which makes this problem a whole lot easier:
template <typename T>
class Base {
public:
void foo(T ) { }
};
template <typename... Ts>
struct Derived: Base<Ts>...
{
using Base<Ts>::foo...;
};
int main()
{
Derived<int, double>().foo(0); // ok! calls Base<int>::foo
}
For the specific library, this code:
template <typename T, unsigned... us>
struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... {
static_assert(sizeof...(us) > 0, "All value types were inelligible!");
};
should look like:
template <typename T, unsigned... us>
struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... {
static_assert(sizeof...(us) > 0, "All value types were inelligible!");
using initializer_leaf<T, us>::operator()...; // (*) <==
};
(although I guess the library is targeting C++11, so I submitted a C++11-compliant fix for it... which is just a bit more verbose).

How to use generic template function to handle objects with different members?

I have looked around a while for a solution to this, however, I might not know the exact definition or language syntax of what I am trying to accomplish, so I decided to post.
I have certain objects/structs like so:
struct A
{
char myChar;
bool hasArray = false;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
hasArray = true;
uint8_t myArray[ARRAY_LEN];
};
I want to create a generic function that can take in both of these object types and to perform common work as well as specific work for the derived struct AA. Something like the following:
template <typename T>
void func(T (&m))
{
if (T.hasArray)
{
// do some processing with m.myArray
std::cout << sizeof(m.myArray) << std::endl;
// ...
}
// common processing
std::cout << "myChar: " << m.myChar << std::endl;
};
I want to be able to call the function like so:
A a;
AA aa;
func(a); // compiler error, this would not work as no array member
func(aa); // this works
Granted this is just an example that illustrates my intent, but it sums up what I would like to do. The actual code is a lot more complex and involved many more objects. I know I can overload, but I want to know if there is a way to do it with one generic function? Also note that I understand why the compiler complains with the sample code I would like to know if there is a workaround or some other c++ functionality that I am missing. I would not like to do any type casting...
- Using c++11 and GCC 4.8.5
This is a C++14 feature of reasonably large complexity. C++17 introduced if constexpr to make this easier; but it is doable.
template<std::size_t I>
using index_t=std::integral_constant<std::size_t, I>;
template<std::size_t I>
constexpr index_t<I> index{};
constexpr inline index_t<0> dispatch_index() { return {}; }
template<class B0, class...Bs,
std::enable_if_t<B0::value, int> =0
>
constexpr index_t<0> dispatch_index( B0, Bs... ) { return {}; }
template<class B0, class...Bs,
std::enable_if_t<!B0::value, int> =0
>
constexpr auto dispatch_index( B0, Bs... ) {
return index< 1 + dispatch_index( decltype(Bs){}...) >;
}
template<class...Bs>
auto dispatch( Bs... ) {
using I = decltype(dispatch_index( decltype(Bs){}... ));
return [](auto&&...args)->decltype(auto){
return std::get<I::value>( std::make_tuple(decltype(args)(args)..., [](auto&&...){}) );
};
}
dispatch( some_test ) returns a lambda that takes auto&&.... It in turn returns the first argument if some_test is of a true-like-type, and the second argument (or [](auto&&...){} if no second argument) if some_test is of a false-like-type.
We then write code to detect your myArray.
namespace details {
template<template<class...>class Z, class=void, class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = typename details::can_apply<Z, void, Ts...>::type;
template<class T>
using myArray_type = decltype( std::declval<T>().myArray );
template<class T>
using has_myArray = can_apply< myArray_type, T >;
and has_myArray<T> is true-like if T has a member .myArray.
We hook these together
dispatch( has_myArray<T>{} )(
[&](auto&& m) {
// do some processing with m.myArray
std::cout << sizeof(m.myArray) << std::endl;
// ...
}
)( m );
and now the lambda in the middle is run if and only if m.myArray is valid.
More complex tests that check for more than just existence can be written, but the above is usually sufficient.
In a non-C++11 compiler like MSVC 2015, replace
std::enable_if_t<B0::value, int> =0
and
std::enable_if_t<!B0::value, int> =0
with
class = std::enable_if_t<B0::value>
and
class = std::enable_if_t<!B0::value>, class=void
respectively. Yes, these are uglier. Go talk to MSVC compiler team.
If your compiler lacks C++14, you'll have to write your own void_t and either write your own enable_if_t or use the ugly longer version using enable_if.
In addition, the template variable index is illegal in C++11. Replace index<blah> with index_t<blah>{}.
The lack of auto&& lambdas makes the above very painful; you may have to convert the lambda to an out-of-line function object. However, auto lambdas where one of the first C++14 features people implemented, often before they finished C++11.
The above code is solid designed, but may contain typos.
Overloading works just fine in your case if you don't want to modify your instances:
#include<iostream>
#include<cstdint>
struct A
{
char myChar;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
uint8_t myArray[ARRAY_LEN];
};
void func(const A &m)
{
std::cout << "myChar: " << m.myChar << std::endl;
};
template <uint8_t AL>
void func(const AA<AL> &m)
{
std::cout << sizeof(m.myArray) << std::endl;
func(static_cast<const A &>(m));
}
int main() {
func(A{});
func(AA<1>{});
}
If you still want to go with a template function and a bit of sfinae, I would probably use something like this instead:
#include<iostream>
#include<cstdint>
struct A
{
char myChar;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
uint8_t myArray[ARRAY_LEN];
};
void func(A &m)
{
std::cout << "myChar: " << m.myChar << std::endl;
}
template <typename T>
auto func(T &m) -> decltype(m.myArray, void())
{
std::cout << sizeof(m.myArray) << std::endl;
A &a = m;
func(a);
}
int main() {
AA<1> aa{};
A a{};
func(a);
func(aa);
}
Note that in both cases you don't actually require the hasArray member data.
there is a way to do it with one generic function?
I don't think so, because if you insert a sizeof(m.myArray) in this function, you can't call it with a type without a myArray member. Even if it is in a part of code that, run time, isn't executed, because the compiler need to compile it.
But, if I understand correctly, your hasArray say if your struct has a myArray member or not. So I suppose you can transform it in a static constexpr member, as follows
struct A
{
static constexpr bool hasArray { false };
char myChar { 'z' };
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
static constexpr bool hasArray { true };
uint8_t myArray[ARRAY_LEN];
};
Now, in func(), you can call a second function, func2(), to choose the two cases: myArray or not myArray. You can use SFINAE for this but (IMHO) is better tag dispatching, in this case. So you can transform your hasArray in a different type
template <typename T>
void func2 (T const & m, std::true_type const &)
{ std::cout << sizeof(m.myArray) << ", "; }
template <typename T>
void func2 (T const &, std::false_type const &)
{ }
template <typename T>
void func(T (&m))
{
func2(m, std::integral_constant<bool, T::hasArray>{});
// common processing
std::cout << "myChar: " << m.myChar << std::endl;
}
Now you can call func() with both types
int main()
{
A a;
AA<12U> aa;
func(a); // print myChar: z
func(aa); // print 12, myChar: z
}
Remember to include type_traits and iostream.

enable_if: minimal example for void member function with no arguments

I am trying to get a better understanding of std::enable_if in C++11 and have been trying to write a minimal example: a class A with a member function void foo() that has different implementations based on the type T from the class template.
The below code gives the desired result, but I am not understanding it fully yet. Why does version V2 work, but not V1? Why is the "redundant" type U required?
#include <iostream>
#include <type_traits>
template <typename T>
class A {
public:
A(T x) : a_(x) {}
// Enable this function if T == int
/* V1 */ // template < typename std::enable_if<std::is_same<T,int>::value,int>::type = 0>
/* V2 */ template <typename U=T, typename std::enable_if<std::is_same<U,int>::value,int>::type = 0>
void foo() { std::cout << "\nINT: " << a_ << "\n"; }
// Enable this function if T == double
template <typename U=T, typename std::enable_if<std::is_same<U,double>::value,int>::type = 0>
void foo() { std::cout << "\nDOUBLE: " << a_ << "\n"; }
private:
T a_;
};
int main() {
A<int> aInt(1); aInt.foo();
A<double> aDouble(3.14); aDouble.foo();
return 0;
}
Is there a better way to achieve the desired result, i.e. for having different implementations of a void foo() function based on a class template parameter?
I know this wont fully answer your question, but it might give you some more ideas and understanding of how you can use std::enable_if.
You could replace your foo member functions with the following and have identical functionality:
template<typename U=T> typename std::enable_if<std::is_same<U,int>::value>::type
foo(){ /* enabled when T is type int */ }
template<typename U=T> typename std::enable_if<std::is_same<U,double>::value>::type
foo(){ /* enabled when T is type double */ }
A while back I gained a pretty good understanding of how enable_if works, but sadly I have forgotten most of its intricacies and just remember the more practical ways to use it.
As for the first question: why V1 doesn't work? SFINAE applies only in overload resolution - V1 however causes error at the point where type A is instantiated, well before foo() overload resolution.
I suppose there are lot's of possible implementations - which is the most appropriate depends on an actual case in question. A common approach would be to defer the part of A that's different for different template types to a helper class.
template <typename T>
class A_Helper;
template <>
class A_Helper<int> {
public:
static void foo( int value ){
std::cout << "INT: " << value << std::endl;
}
};
template <>
class A_Helper<double> {
public:
static void foo( double value ){
std::cout << "DOUBLE: " << value << std::endl;
}
};
template <typename T>
class A {
public:
A( T a ) : a_(a)
{}
void foo(){
A_Helper<T>::foo(a_);
}
private:
T a_;
};
The rest of A can be declared only once in a generic way - only the parts that differ are deferred to a helper. There is a lot of possible variations on that - depending on your requirements...

Invalid use of incomplete type for partial template specialization c++

I am trying to specialize a class method foo(). This works well for full template specialization. However, this does not work with partial template specialization.
Here the example code which compiles fine on GCC and Clang :
#include <iostream>
#include <string>
template <typename Key, typename Value>
struct SimpleKey {
Key key;
Value value;
void foo() const {
std::cout << "base" << std::endl;
}
};
/*
// Uncomment this and it won't work !
template<typename Key>
void SimpleKey<Key, std::string>::foo() const {
std::cout << "partial" << std::endl;
}
*/
template<>
void SimpleKey<int, std::string>::foo() const {
std::cout << "full" << std::endl;
}
int main() {
SimpleKey<double, std::string> key1{1.0,"key1"};
key1.foo();
SimpleKey<int, std::string> key2{1,"key2"};
key2.foo();
}
The error on Clang and GCC I get when uncommenting the relevant code is :
error: invalid use of incomplete type ‘struct SimpleKey >’ void SimpleKey::foo() const {
What should I do to get partial template specialization to work properly with "minimal" efforts ?
You can explicitly specialize a member function of a particular implicit instantiation of a class template. But this is not allowed with partial specializations. If you don't want to write a full partial specialization, you can consider using tag dispatch:
private:
void foo(std::true_type /*value_is_string*/) const { /* "partial" */ }
void foo(std::false_type /*value_is_string*/) const { /* "base" */ }
public:
void foo() const { return foo(std::is_same<Value, std::string>()); }
or refactoring foo() into a base class template that you partially specialize.
It's not possible directly. (It's a shame, this syntax is nice)
But you can do something like this:
namespace detail {
inline void f_(int i) { /* spé for int */}
inline void f_(long i) { /* spé for long*/}
/* other spe... */
}
template<class T>
struct Foo{
void f(T arg) { detail::f_(arg);}
};
It's not as direct, but it's still easily readable.

Checking if a function with a given signature exists in c++

So I was looking for ways to check whether a function with a particular argument exists. I have a templated method which relies on an external function (external from the class) to do the job:
template <class Moo>
void exportDataTo(Moo& ret){
extended_solid_loader(ret, *this);
}
At multiple points in the project I have macros which define extended_solid_loader for different types, but now I want to be able to use a default function if extended_solid_loader hasn't been defined for that particular class type.
I came across this:
Is it possible to write a template to check for a function's existence?
but it seems a little different, in that I'm not checking for a method, but rather a definition of a function with a particular argument type.
Is this possible right now?
You can just provide a function template for extended_solid_loader providing a default implementation, and users who want to use something other than the default implementation just specialize that.
template<class T>
void extended_solid_loader(T & ret, SomeClass & obj) {
// default implementation here
}
template<>
void extended_solid_loader<MooClass>(MooClass & ret, SomeClass & obj) {
// special implementation for MooClass here
}
You don't actually have to do anything particularly special. Just make sure there's a version of that function available to the template and let ADL do the dirty work. Check out this example:
#include <iostream>
namespace bob {
struct X {};
void f(X const&) { std::cout << "bob::f\n"; }
}
namespace ed {
template < typename T >
void f(T const&) { std::cout << "ed::f\n"; }
template < typename T >
struct test
{
void doit() // not called f and no other member so named.
{ f(T()); }
};
}
int main()
{
ed::test<int> test1;
ed::test<bob::X> test2;
test1.doit();
test2.doit();
std::cin.get();
}
Works without the namespace stuff too (non-templates have preference). I just used that to show that ADL will pick it up when you do.
Your original question was interesting. Found a way to do it in C++0x:
template < typename T >
struct fun_exists
{
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename U >
static yes check(decltype(f(U()))*);
template < typename U >
static no check(...);
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
void f(double const&) {}
struct test {};
#include <iostream>
int main()
{
std::cout << fun_exists<double>::value << std::endl;
std::cout << fun_exists<test>::value << std::endl;
std::cin.get();
}