enable_if cannot be used to disable this declaration - c++

I evidently have not enough experience with SFINAE to handle this problem. I actually have the impression that it worked until now, and this kind of problem started to appear like in the last half an hour, everywhere in my code.
#include <iostream>
using namespace std;
template <unsigned int N, typename = typename enable_if <N >= 100> :: type>
struct more_than_99
{
};
int main()
{
more_than_99 <0> c;
}
It says
No type named 'type' in 'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
on the line corresponding to the template declaration. What is going on? I have always used this kind of syntax to enable and disable my template classes and it has always thrown errors on the line of instantiation, rather than on the line of the declaration..
Could you please pedantically explain what am I doing wrong here?

The other answers are correct about why the error happens at the template definition rather than the instantiation.
I need an error to be thrown when trying to instantiate something like `more_than_99 <0> x;' on the line where I try to instantiate it. Something like "hey, this type doesn't exist".
How about something like this?
template <unsigned int N, bool B = (N>=100)>
struct more_than_99;
template <unsigned int N>
struct more_than_99<N,true>
{};
int main()
{
more_than_99 <0> c; // error: implicit instantiation of undefined template 'more_than_99<0, false>'
}
To make it a bit more robust, and to attempt to prevent accidentally instantiating more_than_99<0,true>, this also works (C++11):
template <unsigned int N, bool B>
struct _impl_more_than_99;
template <unsigned int N>
struct _impl_more_than_99<N,true>
{};
template <unsigned int N>
using more_than_99 = _impl_more_than_99<N, (N>=100)>;
int main()
{
more_than_99 <0> c; // error: implicit instantiation of undefined template '_impl_more_than_99<0, false>'
}
Although the error message references the _impl_ type.
You could hide the _impl_ in a detail namespace or something, and just document the more_than_99 alias as if it were the actual type.
However, you will not be able to prevent malicious instantiation of _impl_more_than_99<0,true>.

N is not a dependent non-type template parameter; [temp.dep.temp]/p2
A non-type template-argument is dependent if its type is dependent or the constant expression it specifies is value-dependent.
Therefore instead of a substitution failure occurring, the error is emitted directly from the ill-formed code.

enable_if makes sense if you have a class specialization (or a function overload). It is used to choose between one implementation and another depending on a template parameter, not to trigger an error if the condition is not met.
The idea is "enable this specialization if the condition is met, otherwise fall back to the non-specialized version".
In your case, you probably want something like this:
#include <iostream>
#include <type_traits>
using namespace std;
template<unsigned int N, typename = void >
struct more_than_99
{
// Implementation if N <= 99
enum { value = false };
};
template <unsigned int N>
struct more_than_99<N, typename enable_if <N >= 100> :: type>
{
// Implementation if N >= 100
enum { value = true };
};
int main()
{
cout << more_than_99 <0>::value << endl; //false
cout << more_than_99 <100>::value << endl; //true
}

From http://en.cppreference.com/w/cpp/types/enable_if: (emphasis mine)
This metafunction is a convenient way to leverage SFINAE to conditionally remove functions from overload resolution based on type traits and to provide separate function overloads and specializations for different type traits. std::enable_if can be used as an additional function argument (not applicable to operator overloads), as a return type (not applicable to constructors and destructors), or as a class template or function template parameter.
You cannot use it to enable or disable a class or a struct.
Perhaps you are looking for something like:
namespace detail
{
struct more_than_99 {};
template <bool> Helper;
template <> Helper<true>
{
using type = more_than_99;
};
}
template <unsigned int N> struct selector
{
using type = typename detail::Helper<N >= 100>::type
};
using type = selector<10>::type; // Error.
using type = selector<100>::type; // OK.
// type == detail::more_than_99

Use static assert:
template<unsigned int N>
struct more_than_99
{
static_assert(N >= 100, "N must be more than 99");
};
more_than_99<1> m1;
Results in compilation error something along the lines of:
testM99.cpp:6:3: error: static_assert failed "N must be more than 99"
static_assert(N >= 100, "N must be more than 99");
^ ~~~~~~~~
testM99.cpp:12:19: note: in instantiation of template class 'more_than_99<1>'
requested here
more_than_99<1> m1;

Related

Why can't non-type template parameters be dependent on parameter of specialization?

I've got this code:
#include <iostream>
template <typename num_t, num_t num>
struct factorial {
consteval operator num_t() { return num * factorial<num_t, num - 1>{}; }
};
template <typename num_t>
struct factorial<num_t, 2> {
consteval operator char() { return 2; }
};
int main() {
std::cout << factorial<unsigned long long, 20>{} << '\n';
}
Clang gives me an error under 2 in struct factorial<num_t, 2>. The message is:
error: non-type template argument specializes a template parameter with dependent type 'num_t'
I've looked around a bit and it seems to be because of this part in the standard:
Paragraph [temp.class.spec] 14.5.5/8 of the standard:
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Can someone explain the reasoning behind this section of the standard. It seems to me that they're simply getting in my way. What practical (or even theoretical) value comes with this rule?
Also, I'm more than a little confused about the wording that's being used. Can someone who understands maybe translate it into a more easy-to-understand phrasing?
This is a quick way to fix it:
template <typename num_t, num_t num, typename = void>
struct factorial {
constexpr operator num_t() { return num * factorial<num_t, num - 1>{}; }
};
template <typename num_t, num_t num>
struct factorial<num_t, num, std::enable_if_t<num == 2>> {
constexpr operator char() { return 2; }
};
The reason is (likely), you can't construct num_t num without being aware of what num_t is; thus, compiler cannot match the 2.
The paragraph basically says, template arguments are matched orthogonally, i.e., without co-dependency - this likely makes matching quicker in the compiler.

C++ SFINAE with decltype: substitution failure becomes an error?

This code works:
// Code A
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template <typename T>
struct S {
template <typename Iter, typename = typename enable_if<is_constructible<T, decltype(*(declval<Iter>()))>::value>::type>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
int main()
{
vector<int> v;
S<int> s1(v.begin()); // stdout: S(Iter)
S<int> s2(1); // stdout: S(int)
}
But this code below doesn't work. In the code below, I merely want to inherit std::enable_if, so the class is_iter_of will have member typedef type if the selected version of std::enable_if has member typedef type.
// Code B
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template <typename Iter, typename Target>
struct is_iter_of : public enable_if<is_constructible<Target, decltype(*(declval<Iter>()))>::value> {}
template <typename T>
struct S {
template <typename Iter, typename = typename is_iter_of<Iter, T>::type>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
int main()
{
vector<int> v;
S<int> s1(v.begin());
S<int> s2(1); // this is line 22, error
}
Error message:
In instantiation of 'struct is_iter_of<int, int>':
12:30: required by substitution of 'template<class Iter, class> S<T>::S(Iter) [with Iter = int; <template-parameter-1-2> = <missing>]'
22:16: required from here
8:72: error: invalid type argument of unary '*' (have 'int')
The error message is bewildering: of course I want the template substitution to fail.. so the correct constructor could be selected. Why didn't SFINAE work in Code B? If invalid type argument of unary '*' (have 'int') offends the compiler, the compiler should have issued a same error for Code A as well.
The problem is that the expression *int (*(declval<Iter>())) is invalid, so your template fails. You need to another level of templating, so I suggest a void_t approach:
make is_iter_of by a concept-lite that derives from true_type or fals_type
use enable_if within the definition of your class to enable the iterator constructor.
The key thing to understand is that your constructor before needed a type for typename is_iter_of<Iter, T>::type except that your enable_if in the struct is_iter_of caused the entire thing to be ill-formed. And since there was no fall-back template you had a compiler error.
template<class...>
using voider = void;
template <typename Iter, typename Target, typename = void>
struct is_iter_of : std::false_type{};
template <typename Iter, typename Target>
struct is_iter_of<Iter, Target, voider<decltype(*(declval<Iter>()))>> : std::is_constructible<Target, decltype(*(declval<Iter>()))> {};
template <typename T>
struct S {
template <typename Iter, typename std::enable_if<is_iter_of<Iter, T>::value, int>::type = 0>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
Demo (C++11)
What's happening
The additional voider makes the template specialization not preferred if *(declval<Iter>()) is an ill-formed expression (*int) and so the fallback base template (std::false_type) is chosen.
Else, it will derived from std::is_constructible``. In other words, it can still derive fromstd::false_typeif the expression is well-formed but it's not constructibe, andtrue_type` otherwise.
The thing is you're trying to extend from std::enable_if, but the expression you put inside the enable if may be invalid. Since you are using a class that inherit form that, the class you instanciate inherit from an invalid expression, hence the error.
An easy solution for having a name for your enable_if expression would be to use an alias instead of a class:
template <typename Iter, typename Target>
using is_iter_of = enable_if<is_constructible<Target, decltype(*(declval<Iter>()))>::value>;
SFINAE will still work as expected with an alias.
This is because instancing an alias is part of the function you try to apply SFINAE on. With inheritance, the expression is part of the class being instanciated, not the function. This is why you got a hard error.
The thing is, the is multiple ways SFINAE is applied in your case. Let's take a look at where SFINAE can happen:
enable_if< // here -------v
is_constructible<Target, decltype(*(declval<Iter>()))>::value
>::type
// ^--- here
Indeed, SFINAE will happen because enable_if::type will not exist if the bool parameter is false, causing SFINAE.
But if you look closely, another type might not exist: decltype(*(std::declval<Iter>())). If Iter is int, asking for the type of the star operator makes no sense. So SFINAE if applied there too.
Your solution with inheritance would have work if every class you send as Iter had the * operator available. Since with int it does not exist, you are sending a non existing type to std::is_constructible, making the whole expression forming the base class invalid.
With the alias, the whole expression of using std::enable_if is subject to apply SFINAE. Whereas the base class approach will only apply SFINAE on the result of std::enable_if.

Partial specialization with type nested in a templated class

I'm playing with templates and partial specialization, but there is one specialization I don't know how to write... I'll simplify code to make it easier to read.
Let's condiser
template <typename T>
class x
{
...
};
Usually, I can specialize like this :
class x<a_type>
{
...
};
Also works with templates types :
template <typename T>
class x<std::vector<T>>
{
...
}
Now I would like to make the specialization for a type nested in a templated class:
template <typename T>
class y
{
struct nested_type
{
y a_member;
};
...
};
// Here comes the specialization
template <typename T>
class x<y<T>::nested_type>
{
...
};
This fails. I also tried to put 'typename' before y::nested_type but it did not solved the problem. Compiler error is:
type/value mismatch at argument 1 in template parameter list for ‘template <class T> struct x’
What I want to do seems logical, but I'm not sure if it is possible. I'm using C++0x with g++-4.5. Does anybody know the correct syntax to write such specialization ?
The answer is that you cannot do this specialization. It is not a syntax error, but just something that cannot be realized. You have to see template specializations a little bit like function overloading. The compiler has to take the type argument at the use-site, look at the specializations available, find matches, and select the best one (most specialized one). The problem with your example is that the "find match" step cannot be realized with such a specialization. The compiler can expect "nested_type" to be anything, not necessarily a unique type (as it is in your example), it could also be a nested typedef, for instance. Moreover, the compiler cannot predict that it is already seeing all the specializations of template "y", so even if nested_type is a unique type nested in y (general template), it could be a nested typedef in an upcoming template specialization declaration for template "y".
Just like with function overloading and the matching algorithm used there, the compiler is limited in its capabilities to deduce the type, and what limits it is how much assumptions it can make. If you have a specialization for x<int> and later use x<int>, the match is trivial, no deduction needed, no assumptions needed. If you have a specialization like x<T*> and later use x<int*>, the match is easy, T can be deduced to be int. If you have a specialization like x< y<T>::type > and then use any version of x, how is the compiler supposed to deduce T from y::type? It would have to substitute for T in y all the possible types that exist in the entire world to see if there is one that results in a matching nested type. That's an unreasonable expectation, and that is why the type deduction capabilities of C++ templates stop here. Very often, to know if you should expect the compiler to be able to resolve something, just put yourself in its shoes and see if it is even remotely possible (the answer is usually clear).
You cannot do this partial specialization indeed, but there is a workaround which you can use the achieve desired effect.
Instead of specialization, force the target type to implement what you need.
Here is a minimal example for that:
#include <vector>
#include <iostream>
#include <cassert>
// Default template defines an interface against the target type.
template <class T> struct Traits
{
using TraitsType = typename T::foo_type;
static void foo()
{
T::foo();
}
};
// This is the sample class.
template <class T> struct MyStuff
{
struct NestedType
{
int x;
// It implements the desired features.
using foo_type = int;
static void foo()
{
std::cout << "Using Nested version!\n";
}
};
};
// For built in types you can use specialization.
template <> struct Traits<int>
{
using TraitsType = double;
static void foo()
{
std::cout << "Using int version.\n";
}
};
//... If you can't touch the nested type, the you are SOL.
int main()
{
static_assert(std::is_same<Traits<int>::TraitsType, double>::value);
static_assert(std::is_same<Traits<MyStuff<int>::NestedType>::TraitsType, int>::value);
static_assert(std::is_same<Traits<MyStuff<double>::NestedType>::TraitsType, int>::value);
Traits<int>::foo(); // Prints "Using int version"
Traits<MyStuff<int>::NestedType>::foo(); // Prints "Using Nested version!\n"
Traits<MyStuff<double>::NestedType>::foo(); // Prints "Using Nested version!\n"
return 0;
}

How to deduce class type from method type in C++ templates?

In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?
With the provided code, I get an error of:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(you can fiddle with the snippet at http://ideone.com/8NZkq):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be.
This is because there could be code like this:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
If you can do without the Traits<T> class, you can write Run as:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In this context, Class can be deduced to mean Base
To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
I think this is a non deduced context.
$14.8.2.5/5- "The non-deduced contexts
are: — The nested-name-specifier of a
type that was specified using a
qualified-id."
I think this is the quote that applies in this case. But some template gods need to ratify my understanding.
When the compiler tries to match a template argument, it only considers the primary class type. In other words, when it encounters the expression:
Run(&Base::foo);
...and it's trying to figure out the template parameter for Run, it only considers the type of foo itself, and doesn't consider whatever class foo is a part of.
EDIT:
And the type of foo is bool(Base::*)(void), but what you want the compiler to find is just Base

How to use a template parameter in another template parameter declared before

a template parameter can be used in another template parameter that follows it this way :
template<typename T, T N>
struct s
{
};
But is it possible to reference "T" if it is declared after "N" ?
This does not work :
template<T N, typename T>
struct s
{
};
Can we help the compiler by pre-declaring "T" or doing anything else ?
Thanks by advance.
EDIT : as the first two replies were asking "why are you willing to do that ?" I'll explain the goal :
I would like to make the compiler infer the type "T" in order to make the use of templated classes easier.
For example :
template<typename T, T A, T B>
struct sum
{
static T const value = A + B;
};
This template can be used this way :
sum<int, 1, 2>::value
But it would be better if it could be used this way :
sum<1, 2>::value
Technically it's should be possible because the compiler knows the types of "1" and "2" : "int", and in fact it uses these informations to find the best overload for a function.
So by declaring the template this way :
template<T A, T B, typename T>
struct sum
{
static T const value = A + B;
};
the compiler could use its capability to infer the last parameter from the informations provided by the first and the second one, and then find the best template to instantiate.
Like others say - No this isn't possible, the compiler can't infer the type of T from the non-type template arguments (in the case of functions, it infers types from the function arguments):
14.8.2.4/12:
A template type argument cannot be deduced from the type of a non-type template-argument.
In any case, no deduction will be made for the arguments of a class template anyway. An example for a function template might be
template<int> struct having_int { };
template<typename T, T i> void f(having_int<i>);
int main() { having_int<0> h; f(h); }
In this case, T won't be deduced as int - you have to explicitly specify it.
You can't. I don't see the point why you are doing it too.
Below is rubbish as I didn't read your question properly.
Indeed, I don't see any point in what you are trying to achieve either.
#include <iostream>
template<typename T, T N>
struct s
{
T size() { return N; }
};
int main()
{
s<int, 4> x;
std::cout << x.size()<< '\n';
//s<float, 3.14> f; //this doesn't compile
}
This compiles for me with GCC and Comeau Online.
I think the problem is with the type of T you are trying to use. Non-type template arguments only support integral types, and then pointers to objects with external linkage (or something like that and perhaps a few other very limited things).