SFINAE fails for custom template. Need to understand why - c++11

My code needs to test various pixel types for "validity". For example, floating point pixels are invalid if they report true for std::isnan().
So I have a "validator" template struct that I specialize for my various pixel types (here, just for float). My code uses a global template function to invoke the right overload through SFINAE
// Dummy implementation breaks compilation if no overload found.
template<class PEL, typename Enable=void> struct pixel_validator { };
template<class PEL>
struct pixel_validator<PEL, typename std::enable_if<std::is_floating_point<PEL>::value>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
template<class PEL>
inline bool is_valid_pixel(const PEL& p)
{
// Dispatch to validator above
return pixel_validator<PEL>::validate(p);
};
void main
{
float x = 1.0f;
std::cout << "is it valid ?" << std::boolalpha << is_valid_pixel(x);
}
And this example works just fine. The pixel_validator specialization for float is chosen. All is well.
But then I tried to reduce the verbosity of my template expressions for clarity via a custom version of "std::enable_if" specifically for float.
template<class T, class VAL=T>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{};
So now instead of writing this:
std::enable_if<std::is_floating_point<PEL>::value>::type
I can write
enable_if_floating<PEL>::value
... so my validator becomes:
template<class PEL>
struct pixel_validator<PEL, typename enable_if_floating<PEL>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
Unfortunately, the moment that I change my "pixel_validator" to use it, the code fails to build. My enable_if_floating does not work and so Visual Studio cannot find the appropriate specialization. My output is not surprising then.
1>------ Build started: Project: TestApp7, Configuration: Debug Win32 ------
1>TestApp7.cpp
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: 'validate': is not a member of 'pixel_validator<PEL,void>'
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: with
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: [
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(62,34): error C2039: ]
1>C:\Test\TestApp7\TestApp7.cpp(62): message : see declaration of 'pixel_validator<PEL,void>'
1>C:\Test\TestApp7\TestApp7.cpp(62): message : with
1>C:\Test\TestApp7\TestApp7.cpp(62): message : [
1>C:\Test\TestApp7\TestApp7.cpp(62): message : PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(62): message : ]
1>C:\Test\TestApp7\TestApp7.cpp(82): message : see reference to function template instantiation 'bool is_valid_pixel<float>(const PEL &)' being compiled
1>C:\Test\TestApp7\TestApp7.cpp(82): message : with
1>C:\Test\TestApp7\TestApp7.cpp(82): message : [
1>C:\Test\TestApp7\TestApp7.cpp(82): message : PEL=float
1>C:\Test\TestApp7\TestApp7.cpp(82): message : ]
1>C:\Test\TestApp7\TestApp7.cpp(62,1): error C3861: 'validate': identifier not found
1>Done building project "TestApp7.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
My question is, why? What is wrong with my enable_if_floating?
Note: I even put this code in my main(), just for sanity checking. If my template were bad, I would expect the static_assert() to fail, but it does not.
// Sanity check #2. Does my enable_if_floating test reports that float
// enables because it's numeric? If not then the static_assert below should fail
using float_type = enable_if_floating<float>::type;
static_assert(std::is_same_v<float_type, float>, "Not same as float...");
Note also: My real world code uses a predicate that saves a whole lot more space than in this simple example

Not sure is the only problem but is a problem.
If you write
template<class T, class VAL=T>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{};
the default returned type is T where, for std::is_enable_if, is void.
So
template<class PEL>
struct pixel_validator<PEL, typename enable_if_floating<PEL>::type>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
become, when PEL is a floating point type,
template<class PEL> // .....VVV should be void, not PEL
struct pixel_validator<PEL, PEL>
{
static bool validate(const PEL& p) { return !std::isnan(p); }
};
that doesn't matches the pixel_validator declaration (and main definition)
template<class PEL, typename Enable=void>
struct pixel_validator
{ };
because the expected second type is void, not PEL.
I see two possible alternative solutions: or you use void as default value for enable_is_floating second template parameter
// ...........................VVVV
template<class T, class VAL = void>
struct enable_if_floating
: std::enable_if<std::is_floating_point<T>::value, VAL>
{ };
or you use PEL as default value for pixel_validator second template parameter
template <typename PEL, typename = PEL>
struct pixel_validator
{ };
I suggest the first one to homogeneity with std::enable_if and standard C++ library.

Related

C++11: properly expand template parameter pack in trailing return type

I am trying to translate run-time constant to compile-time constant in my C++11 program using switch statement. I have enum SomeEnum {A, B, C};, and depending on its value I want to call the template function f<A>(), f<B>() or f<C>(). I have lots of template functions in my code that depend on SomeEnum (as well as other template parameters), so I decided to make dedicated dispatch function. Here is the code I am trying to compile:
#include <utility>
enum SomeEnum {
A, B, C
};
template<template<SomeEnum, typename...> class FUNCTOR, typename ...OTHERS, typename ...ARGS> inline auto dispatch (
SomeEnum const type,
ARGS&&... args
) -> decltype( FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...) ) { //Problem here
switch(type) {
case A:
return FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...);
case B:
return FUNCTOR<B, OTHERS...>::function(std::forward<ARGS>(args)...);
case C:
return FUNCTOR<C, OTHERS...>::function(std::forward<ARGS>(args)...);
default:
//Do not call any function if enum value is wrong, just return something:
return decltype( FUNCTOR<A, OTHERS...>::function(std::forward<ARGS>(args)...) )();
}
}
template<SomeEnum T> struct TemplateFunctor1 {
static inline int function(int) { return 0; }
};
template<SomeEnum T, class OTHER> struct TemplateFunctor2 {
static inline int function(int) { return 0; }
};
int main(void) {
dispatch<TemplateFunctor1>(B, 0); //Problem here!
dispatch<TemplateFunctor2, int>(B, 0);
return 0;
}
(I do not need to handle the case when function return type depends on template parameter)
I am getting an error while compiling the line dispatch<TemplateFunctor1>(B, 0);, where is only one template parameter required by TemplateFunctor1. The error messages are following:
error: no matching function for call to 'dispatch(SomeEnum, int)'
note: candidate: template<template<SomeEnum <anonymous>, class ...> class FUNCTOR, class ... OTHERS, class ... ARGS> decltype (FUNCTOR<(SomeEnum)0u, OTHERS ...>::function((forward<ARGS>)(dispatch::args)...)) dispatch(SomeEnum, ARGS&& ...)
note: template argument deduction/substitution failed
error: wrong number of template arguments (2, should be 1) in this part of code: FUNCTOR<A, OTHERS...> of trailing return type.
So I tried to change FUNCTOR<A, OTHERS...> in trailing return type to FUNCTOR<A>, then the line dispatch<TemplateFunctor2, int>(B, 0); cannot be compiled. It says that I provided wrong number of template parameters (1, should be 2), which is quite an expected error.
What I do not understand here is why the same decltype() construction works in default switch branch, but does not work in the trailing return type?
I can fix my code by changing the standard to C++14 and by removing trailing return type completely, but then I will not understand what is going on here.
I also tried different compilers (ICC, GCC, Clang), and all of them giving similar error messages, so it cannot be a compiler error here.
I don't know what the problem is, but this workaround seems to be working:
template <template<SomeEnum, typename...> class FUNCTOR, typename... X>
struct Wrapper
{
using Type = FUNCTOR<A, X...>;
};
template<template<SomeEnum, typename...> class FUNCTOR, typename ...OTHERS, typename ...ARGS>
inline auto dispatch (
SomeEnum const type,
ARGS&&... args
) -> decltype( Wrapper<FUNCTOR, OTHERS...>::Type::function(std::forward<ARGS>(args)...) ) { //No problem here

CRTP traits only working with templated derived class

I have seen an idiom for using Derived type traits in the base class of a CRTP pattern that looks like this:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
template <typename T>
struct Derived1 : Base<Derived1<T>>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <typename T>
struct traits<Derived1<T>> {
using size_type = size_t;
};
int main()
{
using T = float;
Derived1<T> d1;
d1.print();
}
My understanding is that the purpose of the idiom is to delay the instantiation of the Base class's size_type. What I am confused by is the fact that this pattern only seems to work if the derived class is itself templated. For instance, if we change the code to:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <>
struct traits<Derived1> {
using size_type = size_t;
};
int main()
{
Derived1 d1;
d1.print();
}
then we get the error
prog.cc: In instantiation of 'struct Base<Derived1>':
prog.cc:21:19: required from here
prog.cc:18:58: error: invalid use of incomplete type 'struct traits<Derived1>'
using size_type = typename traits<Derived>::size_type;
^
prog.cc:14:8: note: declaration of 'struct traits<Derived1>'
struct traits;
^~~~~~
prog.cc: In function 'int main()':
prog.cc:33:9: error: 'Derived1' is not a template
Derived1<float> d1;
Could somebody give me an explanation indicating why the templated derived class compiles, but the untemplated class does not?
The issue you're seeing has nothing to do with CRTP.
Here's what the standard mentions.
If a class template has been declared, but not defined, at the point of instantiation (13.7.4.1),
the instantiation yields an incomplete class type (6.7). [Example:
template<class T> class X; X<char> ch; // error: incomplete type
X<char>
Your traits has only been declared at the point of instantiation of Base<Derived>, hence as per the standard(see above extraction from the standard), struct traits<Derived> yields an incomplete type.
You should reorder the code so that it sees the traits<Derived> specialization when Base<Derived> gets instantiated.
The compilation error you are seeing has nothing to do with CRTP, it's just a bit of a mish-mash of dependencies.
In the code without the templation, your "Base" struct needs the definition of the specialized "traits" struct but it only appears afterwards, so it tries to use the incomplete type it saw in the declaration above.
To get the code to work you need to have the "traits" specialization before the Base declaration, which requires you to also add a declaration of Derived 1, here is a compiling code:
class Derived1;
template<typename Derived>
struct traits;
template <>
struct traits<Derived1> {
using size_type = size_t;
};
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
int main()
{
Derived1 d1;
d1.print();
}

c++ std::shared_ptr Error C2664

I am using a std::shared_ptr to point to a Node
template<typename T>
class A
{
class Node
{
T data;
std::shared_ptr<Node> link;
Node(T data, std::shared_ptr<Node> link);
};
void push(T data);
std::shared_ptr<Node> top;
};
template<typename T>
A<T>::Node::Node(T data, std::shared_ptr<typename A<T>::Node> link) :
data(data), link(link)
{
}
template<typename T>
void A<T>::push(T item)
{
if (top == nullptr)
{
top = std::make_shared<typename A<T>::Node>(new typename
A<T>::Node(item, nullptr));
}
else
{
top = std::make_shared<typename A<T>::Node>(new typename A<T>::Node(item, top));
}
}
The resulting declarations and definitions results in the compiler error
Severity Code Description Project File Line Suppression State
Error C2664 'Stack::Node::Node(const Stack::Node &)': cannot convert argument 1 from 'Stack::Node *' to 'const Stack::Node &' memory 901
What do I need to change to conform to <memory>?
A constructor of std::shared_ptr<T> accepts a pointer to T which you have created with new.
The function std::make_shared<T>(args...) does the new for you instead. The arguments you pass to make_shared will be passed on to the constructor of T. So you should almost never pass it a pointer created by new (unless you really want to new a T, and then pass that pointer as an argument to create another T!).
So for example, instead of:
std::make_shared<typename A<T>::Node>(
new typename A<T>::Node(item, top))
do just:
std::make_shared<typename A<T>::Node>(item, top)
(By the way, you don't actually need most of those typename A<T>:: qualifiers. Just plain Node is in scope whenever you're in the scope of A<T> or A<T>::Node, both in the class definitions and member definitions of that class after the member name. A<T>::Node without the typename would also work in those contexts because of the "member of the current instantiation" rule.)

Deducing Function Parameter types using parameter packs

I am trying to call function using pointer to member function pointer and parameter packs. Given Below is code:
class DemoClass {
public:
void Printer(const DemoClass& sc, const int& i) {
}
};
template<typename R, typename T, typename ... Args/*, typename ... Params*/>
void MakeMemberActionDemoClass(R(T::*memberFunction)(Args...), Args&& ... args)
{
}
int main()
{
DemoClass d;
int z;
MakeMemberActionDemoClass(&DemoClass::Printer, d, z);
}
I get following error:
error C2782: 'void MakeMemberActionDemoClass(R (__thiscall T::* )(Args...),Args &&...)' : template parameter 'Args' is ambiguous
1> could be 'const DemoClass&, const int&'
1> or 'DemoClass&, int&'
If I remove && in last parameter of MakeMemberActionDemoClass, only difference in error is following:
1> could be 'const DemoClass&, const int&'
1> or 'DemoClass, int'
What should I do so that parameter types will be deduced correctly?
Thanks in advance,
Both instances of Args are in a deducible context. They must produce the same type, or your compiler complains it is ambiguous.
One way is to block deduction in one or the other context. The other way is to stop connecting them.
template<class T>struct tag_t{using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<class T>using block_deduction=type_t<tag_t<T>>;
template<class R, class T, class...Args>
void MakeMemberActionDemoClass(
R(T::*memberFunction)(Args...),
block_deduction<Args>... args
)
{
}
this has the cost of possibly copying values twice.
template<class R, class T, class...Args, class...Params>
auto MakeMemberActionDemoClass(
R(T::*memberFunction)(Args...),
Params&&... params
)
->decltype( (std::declval<T*>()->*memberFunction)( std::declval<Params>()... ) )
{
}
will deduce them correctly and let you perfect forward into memberFunction and SFINAE early enough to detect overload failures.

C++11: using decltype on invalid expressions

Say I have a struct (in real life, that's an automaton):
struct automaton
{
bool get_final() const { return final; }
void set_final() { final = true; }
bool final = false;
};
for which I want to provide a view that sees it transposed (iow, reversed, or mirrored). Because I have more than just a single automaton class, I have a class template that wraps my automaton (I really want composition, not inheritance), and bounces all the function calls to the wrapped automaton, reversing what needs to be. For sake of simplicity, here, it just forwards the calls.
By hand, I'd get
template <typename Aut>
struct transposed_by_hand
{
Aut& aut;
auto get_final() const -> bool
{
return aut.get_final();
}
auto set_final() -> void
{
aut.set_final();
}
};
But there are many functions, and I don't want to hard-code so much information (the function signature) in the wrapper. Thanks to variadic templates and perfect forwarding for the incoming arguments, and decltype for the result, it's quite easy to have one macro to factor the definition of all the const member-functions, and another macro for non-const member functions (the difference being precisely the const). Basically, in this case it boils down to this:
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> decltype(aut.set_final())
{
aut.set_final();
}
};
This works well for non-const automata, but breaks if I wrap a const automaton:
int main()
{
const automaton aut;
transposed_by_hand<const automaton> trh = { aut };
transposed_with_decltype<const automaton> trd = { aut };
}
My compilers complain that (G++ 4.9):
f.cc: In instantiation of 'struct transposed_with_decltype<const automaton>':
f.cc:44:49: required from here
f.cc:34:12: error: passing 'const automaton' as 'this' argument of 'void automaton::set_final()' discards qualifiers [-fpermissive]
auto set_final() -> decltype(aut.set_final())
^
and (Clang++ 3.3):
f.cc:42:23: error: default initialization of an object of const type 'const automaton' requires a user-provided default constructor
const automaton aut;
^
f.cc:34:36: error: member function 'set_final' not viable: 'this' argument has type 'const automaton', but function is not marked const
auto set_final() -> decltype(aut.set_final())
^~~
f.cc:44:49: note: in instantiation of template class 'transposed_with_decltype<const automaton>' requested here
transposed_with_decltype<const automaton> trd = { aut };
^
f.cc:6:12: note: 'set_final' declared here
void set_final() { final = true; }
^
2 errors generated.
And they are right! The expression in the decltype is breaking the const-ness of the wrapped automaton. Yet, I am not going to use this function, I swear. Just like I will not use the corresponding one wrapped by hand.
So my question is: is there a means to write the definition of the wrapping set_final so that I don't have to spell out its signature (input and output)? I have tried to use std::enable_if, but it changes nothing to the problem here. And anyway, it would need that the compiler be lazy, and accepts not to evaluate the second parameter of std::enable_if if it does not need to...
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> typename std::enable_if<!std::is_const<Aut>::value,
decltype(aut.set_final())>::type
{
aut.set_final();
}
};
Thanks in advance.
I can get it to work (using GCC 4.6) just by using the advice Xeo mentions in his comment. That is, I turn the function into a trivial template, like so:
template<typename = void>
auto set_final() -> decltype(aut.set_final()) {
return aut.set_final();
}
== EDIT ==
Luc Danton comments below that a more recent GCC may reject the code, complaining that the decltype isn't dependent. I only have 4.6 here, but perhaps this could be worked around using something like this:
template<typename KLUDGE = int>
auto set_final() -> decltype((&aut+KLUDGE(0))->set_final()) {
return aut.set_final();
}
YMMV.

Resources