Detect operator++ signature with std::is_detected_exact - c++

I want to detect at compile time if a given type has the pre-increment operator with the library fundamentals TS v2 type_traits' is_detected_exact helper - however, it seems like I either misunderstood this helper or I supplied the wrong parameters, the following code does not compile:
#include <experimental/type_traits>
template<typename T>
using operator_plusplus_t = decltype(&T::operator++);
template<typename T>
using has_pre_increment = std::experimental::is_detected_exact<T&, operator_plusplus_t, T>;
struct incrementer
{
incrementer& operator++() { return *this; };
};
static_assert(has_pre_increment<incrementer>::value, "type does not have pre increment");
The error I get is this one (the static_assert fails):
<source>:14:15: error: static assertion failed: type does not have pre increment
static_assert(has_pre_increment<incrementer>::value, "type does not have pre increment");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 1
https://godbolt.org/z/-zoUd9
I was expecting this code to compile since the "incrementer" struct has a operator++ method with no arguments returning a reference to its type ...
Maybe you can point me in the right direction, thanks in advance!

You can use decltype(++std::declval<T>()) instead.
https://godbolt.org/z/h_INw-

Related

How to query whether a type models Struct?

Given a type T, I'd like to know whether that type satisfies Boost.Hana's Struct concept. In other words, I would like to construct a metafunction is_struct_v such that for
struct foo_t { int x; }
BOOST_HANA_ADAPT_STRUCT(foo_t, x);
the following code compiles:
static_assert(is_struct_v<foo_t>);
whereas is_struct_v<std::vector<int>> should return false.
My guess was that hana's is_valid "function" is appropriate for this, however, I'm unable to bend the compiler to my will. Here is my attempt:
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <typename TypeTag>
constexpr auto is_struct(TypeTag t) {
auto has_members = hana::is_valid([](auto v)
-> decltype((void)(boost::hana::members(hana::traits::declval(v))))
{});
return has_members(t);
}
template <typename T>
constexpr bool is_struct_v = is_struct(boost::hana::type_c<T>);
This does return true for the foo_t case, but when I attempt to apply is_struct_v to std::vector<int>, I get the following error in clang (trunk):
static_assert failed due to requirement 'hana::Struct<S>::value'
UPDATE: I've solved my own problem; see answer below. That said, I would still appreciate an explanation of why the version which uses hana::members doesn't work. I find it odd that the static_assert triggers a compile time error because I thought is_valid is supposed to SFINAE that away. What am I missing?
Well, that was silly. It was only after posting that I realized I could use the error message to solve my problem! So hana::Struct<foo_t>::value is true, while hana::Struct<std::vector<int>> is false.

Using generic operator->* as rvalue

The compilation process of:
template <typename T> T GetMember(const T STRUCT_T::* member)
{
STRUCT_T* pStruct = GetStruct();
...
// read value
T retVal = pStruct->*member; // compiler assertion here
ReleaseStruct();
return retVal;
}
ends due to compiler assertion when used with a non-basic type T:
Tool internal error:
Internal Error: [Front end]: assertion failed at:
"....\Translator\compiler_core\src\parser\edg\lower_il.c", line 13411
Shocked by the fact that IAR compiler's "lower_il.c" has at least 13,411 lines and non of them is a proper generic operator->*(), I found it even stranger that the following function do compile with a non-basic type T:
template <typename T> void SetMember(T STRUCT_T::* member, const T& value)
{
STRUCT_T* pStruct = GetStruct();
...
// write value
pStruct->*member = value; // no compiler assertion here
ReleaseStruct();
}
I guess the result of the generic operator is OK as lvalue but not as rvalue. Unconsting the parameter didn't help.
Any ideas of cause and solution?
We can tell from edg\lower_il.c that this is the EDG frontend, not a proprietary IAR parser. EDG is well-maintained and well-respected, and you can play with a newer version at http://gcc.godbolt.org/ . (Select ICC from the compiler menu.)
The filename suggests that it's dealing with a lower-level intermediate representation, not building the initial AST. There may be a problem translating the pointer-to-member access to more primitive operations. Or the flag might be appearing on the wrong line. Internal errors aren't always precise. An SSCCE would be better.
IAR service pack 6.70.2 solved the problem.

How to use the auto and decltype keywords to ease template argument deduction?

I am implementing the Merge sort algorithm. The problem is when I try to use a vector of automatically deduced types within the algorithm.
template <typename TIterator, typename TCompare>
void mergeSort(TIterator begin, TIterator end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//... // and not a reference
}
This works.
But once I make the algorithm pass the TIterators by constant reference, I get an error which I never got in my whole life:
template <typename TIterator, typename TCompare>
void mergeSort(const TIterator& begin, const TIterator& end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//...
}
results in:
In function 'void mergeSort(const TIterator&, const TIterator&, TCompare)':
internal compiler error: in type_unification_real, at cp/pt.c:14176
I am using g++ 4.6.3 on Ubuntu
What went wrong?
An internal compiler error occurs whenever the compiler fails, which means that you found a bug. This is the reason while early adoption of new standards is usually called the bleeding edge: sometimes, it makes you bleed ;)
There might be something wrong with your code, or there might not. It's not possible to tell from this output alone. What is certain is that the compiler does not support it so you might want to change it instead.
In particular, lookup std::iterator_traits<> to see all the things you can deduce from an iterator's type:
typename std::iterator_traits<TIterator>::value_type help = *begin;
// ::reference
// ::pointer
// ...
By circumventing the automatic deduction, you will probably be able to get past the compiler bug.
Note: if you wish to report the bug, which is certainly laudable, you will be asked to produce a preprocessed file reproducing the issue. This file should be as small as possible. It can be generated using -E on the gcc command line and generally ends up with the .ii extension.

Why is this a compiler error? (g++)

So I'm attempting to utilize a generic compare functor in my utility class.
I attempt to define it and call it like so
template <class T>
bool AVL_tree<T>::avl_insert(AVL_Node<T> *& top, const AVL_Node<T> * insertNode, bool & taller) {
std::binary_function<T,T,bool>::first_argument_type insertNodeValue;
insertNodeValue = insertNode->data;
std::binary_function<T,T,bool>::second_argument_type topValue;
topValue = insertNode->data;
std::binary_function<T,T,bool>::result_type cmp_result;
cmp_result = comparer(insertNodeValue,topValue);
std::binary_function<T,T,bool>::result_type cmp_result2;
cmp_result2 = comparer(topValue,insertNodeValue);
//Function continues from here
}
The specific compiler error is expected ; before insertNodeValue
This error is repeated for topValue and cmp_result;
I don't really understand why this is a syntax error, I'm working off this reference:
http://www.cplusplus.com/reference/std/functional/binary_function/
It's a dependent name, so it requires the typename keyword:
typename std::binary_function<T,T,bool>::first_argument_type insertNodeValue;
Similarly for others. See the SO FAQ entry on dependent names.
Given that these are dependent types, your first step should probably be to add typename:
typename std::binary_function<T,T,bool>::first_argument_type insertNodeValue;

how to solve following problem in C++?

I have one template function which will take a pointer type and i have instantiated it before calling.
i have written function with its dummy implementation as follows:
template<T>fun_name( const T *p )
{
//written functionality which will give me class name that i will store into string Variable
e.g. i got output like this string Var = "First_class" or string Var = "Second_class"
//Using this class name i will call one function of that class
if(Var == "Fisrt_class")
{
First_class::static_function_name(p);
}
if(Var == "Second_class")
{
Second_class::static_function_name(p);
}
}
and in global scope i instantiated this function for two variables as like below:
template<first_class>static_function_name(const First_class *)
template<Second_class>static_function_name(const Second_class *)
above code gives me error that
error: no matching function call in Second_class::static_function_class(const Fisrt_class*)
error: no matching function call in First_class::static_function_class(const Second_class*)
thanks in advance!
I think this :
template<typename T> // template<class T> is equally valid!
void fun_name( const T *p )
{
T::static_function_name(p);
}
is enough!
Two more errors is fixed in the above code:
Mention the keyword typename in template<T> in your code. You can also write template<class T> which is equally valid.
Mention the return type of the function template as well.
Your function template "calls" each of the static functions in each class. Even though program flow may never get to one of the calls, the compiler still has to figure out the code for each of them.
So when you instantiate:
template<first_class>fun_name(const first_class*)
the compiler tries to compile the entire function with T = first_class, which means at some point inside the function, it will try to compile the function call:
Second_class::static_function_name(p);
But since variable p is a pointer to first_class, the compiler doesn't find the function.
If you want conditional compilation, try specializing your function instead so the compiler only compiles the function call you intended for each type:
template <T> fun_name (const T* p);
template <> fun_name<first_class>(const first_class* p) {
first_class::static_function_name(p);
}
template <> fun_name<second_class>(const second_class* p) {
second_class::static_function_name(p);
}
Alternatively, you can use member functions which seem to be intended for what you are trying to do here. Then you can create objects and call the functions directly:
first_class f;
second_class s;
f.function();
s.function();
try changing to ,
template<typename T>
void fun_name( const T *p )
{
T::static_function_name(p);
}