Deduction of alias template - c++

This question is partially motivated by this previous question.
I am aware that alias templates are not deduced, except, in c++20, for class template argument deduction.
For this reason, this code does not compile
#include <iostream>
template <bool Bv>
struct A;
template <>
struct A<true> {
void print() const { std::cout << "True" << std::endl; }
};
template <>
struct A<false> {
void print() const { std::cout << "False" << std::endl; }
};
enum class Btypes : int { cat, dog, wolf };
template <Btypes bt>
using B = A<(bt == Btypes::dog) ? true : false>;
template <Btypes bt>
void callB(const B<bt>& b)
{
b.print();
}
int main()
{
B<Btypes::dog> b;
callB(b); // error: no matching function for call to ‘callB(B<Btypes::dog>&)‘
return 0;
}
This answer details some subtleties on how a deduction of alias templates could/or could not work.
I am however interested in a simpler case of non-type template parameters, like in the code above.
It seems to me reasonable that a template deduction could be possible without ambiguities, since the non-type template parameters involved can only take a finite amount of values.
Is there a way, within c++17, to circumvent the lack of template parameter deduction for a class like in the code above, with non-type template parameters?
That is, to make the code legal without changing the definition/signature of the function callB (and keeping the alias)?

Related

Specialisation of member function templates in c++

I want to create a generic class containing a method displaying one message if the type of the class is int and the other when it's double. Here's my code:
template<class T>
class A {
public:
template <T> void B();
};
template<class T>
void A<int>::B{
//some code here
}
template<class T>
void A<double>::B{
//some code here
}
I got the following errors:
'double': illegal type for non-type template parameter '__formal'
'A<int>::B': unable to match function definition to an existing declaration
Thanks in advance for any solutions.
A couple of things:
There's no reason for B to be a template. You want to specialize for A
B is a method. Methods accept parameters. When defining the method, you omitted the parenthesis ()
Template specialization always involves an empty template parameter <>
Code:
template<class T>
class A {
public:
void B();
};
template<>
void A<int>::B(){
std::cout << "A<int>::B" << std::endl;
}
template<>
void A<double>::B(){
std::cout << "A<double>::B" << std::endl;
}
Demo
If you feel compelled to make B a template, I should note that in general one does not perform template specialization on functions. This is primarily because they cannot be partially specialized, and it's almost always better to write an overload. In your case, B takes no arguments, so there's some argument to be made in favor of specialization.
More often than not, one would use a tag dispatching approach instead, coupled with a helper function so that they can choose their desired function by taking advantage of overloading instead. Here's a simple example of tag dispatching for your case:
template<class T>
class A {
public:
template<class U>
void B()
{
B(ATag<U>{});
}
private:
template<class U>
struct ATag{};
void B(ATag<int>)
{
std::cout << "B<int>" << std::endl;
}
void B(ATag<double>)
{
std::cout << "B<double>" << std::endl;
}
};
tag dispatch demo

class member overload (or specialization) based on different enum values

Is it possible to overload or specialize class member functions based on given enum values?
enum class Type {
TypeA,
TypeB,
TypeC
};
class Foo {
public:
template <Type t, typename R = std::enable_if_t<t==Type::TypeA, int>>
R get() {
return 1;
}
template <Type t, typename R = std::enable_if_t<t==Type::TypeB, double>>
R get() {
return 2;
}
template <Type t, typename R= std::enable_if_t<t==Type::TypeC, float>>
R get() {
return 3;
}
};
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
The compile complain about overloading on above code snippet.
One pretty standard way to fix it is to put the std::enable_if clause in the return type of the function, rather than in the template parameters like that.
This compiles for me at c++11 standard.
#include <iostream>
#include <type_traits>
enum class Type {
TypeA,
TypeB,
TypeC
};
class Foo {
public:
template <Type t>
typename std::enable_if<t==Type::TypeA, int>::type get() {
return 1;
}
template <Type t>
typename std::enable_if<t==Type::TypeB, double>::type get() {
return 2;
}
template <Type t>
typename std::enable_if<t==Type::TypeC, float>::type get() {
return 3;
}
};
static_assert(std::is_same<int, decltype( std::declval<Foo>().get<Type::TypeA>())>::value, "");
static_assert(std::is_same<double, decltype( std::declval<Foo>().get<Type::TypeB>())>::value, "");
static_assert(std::is_same<float, decltype( std::declval<Foo>().get<Type::TypeC>())>::value, "");
int main() {
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
}
I'm not sure if I can explain in detail why this change makes such a difference for the compiler.
However, consider the following. With your version, although you are never actually instantiating get with two explicit template parameters, technically all three of those member functions templates can "collide" and produce functions with exactly the same name. Because, if you did instantiate get<Type::TypeB, int>, then it would have the same return type, input parameters, and name as get<Type::TypeA>. C++ does not support function template specialization, it would make overload resolution rules very complicated. So having function templates with the potential to collide like this can make the compiler very upset.
When you do it the way I showed, there is no possibility that the templates can collide and produce a function with the same name and signature.
You can avoid the use of std::enable_if mapping the Type and return types specializing a simple struct (Bar, in the following example)
#include <iostream>
enum class Type {
TypeA,
TypeB,
TypeC
};
template <Type t>
struct Bar;
template <>
struct Bar<Type::TypeA>
{ using type = int; };
template <>
struct Bar<Type::TypeB>
{ using type = double; };
template <>
struct Bar<Type::TypeC>
{ using type = float; };
class Foo {
public:
template <Type t>
typename Bar<t>::type get();
};
template <>
Bar<Type::TypeA>::type Foo::get<Type::TypeA> ()
{ return 1; }
template <>
Bar<Type::TypeB>::type Foo::get<Type::TypeB> ()
{ return 2.2; }
template <>
Bar<Type::TypeC>::type Foo::get<Type::TypeC> ()
{ return 3.5f; }
int main ()
{
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
return 0;
}
Your example doesn't compile because defaulted type templated parameters are not part of the function signature. So as far as the compiler is concerned, you are defining the same function multiple times, which is illegal. Instead, you need to use a defaulted non-type template parameter.
class Foo {
public:
template <Type t, std::enable_if_t<t==Type::TypeA, int> = 0>
int get() {
return 1;
}
template <Type t, std::enable_if_t<t==Type::TypeB, int> = 0>
double get() {
return 2;
}
template <Type t, std::enable_if_t<t==Type::TypeC, int> = 0>
float get() {
return 3;
}
};
Two working solutions are already posted; so why did I post this one? Well, I like it better. To be concrete:
It keeps what the function actually takes and returns separate from when it's enabled. This makes the function easier to read and understand. You can pull the code snippet from the second argument into a tiny macro called REQUIRE or similar; this makes it extremely clear what's going on. Neither of the other two answers posted have this property.
This technique is more universal; it can be used in slightly different situations with constructors, which don't return anything and cannot be used with the other two solutions
max66's approach of mapping the enum to a type is nice and it's something you should be aware of. It's more appropriate though when you can write the body generically; if you have to write out every implementation body separately anyhow, it only adds boilerplate (IMHO). Also you should be aware that a solution based on specialization is fragile; it doesn't work if there's a second template parameter nor if the class Foo is a class template, because of the restrictions on specialization function templates.
With the macro I mentioned above you could write it this way:
template <Type t, REQUIRE(t==Type::TypeA)>
int get() {
return 1;
}
// ...
Which I think is as good as it gets.

Specializations only for C++ template function with enum non-type template parameter

This question is related to this one except that rather than dealing with typename template parameters, I am trying to use an enum non-type template parameter.
Is it possible to have a templated (class member function) with only specializations, no general (working) definition in the case of non-type template parameter?
I was able to get one version working, by declaration in the class body and providing specializations only, but any misuse calling with a non-defined template parameter doesn't produce an error until linking. What's worse is the missing symbol cryptically refers to the enum's integral value and not its name, so it would be confusing to other developers.
I was able to get the BOOST_STATIC_ASSERT technique from the referenced question to work for typename template parameter only.
This code demonstrates the idea. I don't want the CAT-version call to compile:
#include <iostream>
#include <boost/static_assert.hpp>
// CLASS HEADER FILE:
struct foo_class
{
enum AllowedTypes { DOG, CAT };
template <AllowedTypes type>
void add_one_third( double bar ) const
{
BOOST_STATIC_ASSERT_MSG(sizeof(type)==0, "enum type not supported.");
}
};
// CLASS SOURCE FILE
template<>
void foo_class::add_one_third<foo_class::DOG>( double bar ) const
{
std::cout << "DOG specialization: " << bar + 1./3. << std::endl;
}
// USER SOURCE FILE
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.add_one_third<foo_class::DOG>(3.0); // should succeed
// Compilation fails with or without the following line:
a.add_one_third<foo_class::CAT>(3.0); // should fail at compile-time
return 0;
}
Background:
I have a class member function that takes an enum "ArgType" and a name.
void declareKernelArgument( ArgType type, std::string name );
The definition has turned into an if..else..if..else list for the half-dozen or so allowed ArgType cases. I also have to have final case that throws an exception for an not-allowed ArgType. I'm thinking it would be cleaner to move ArgType to a template parameter, and provide a specialization for each allowed ArgType. Misuse would be caught at compile-time.
With partial specialization of a structure inside the class:
#include <iostream>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
private:
template <AllowedTypes type, typename T>
struct AddOneThird;
template <typename T>
struct AddOneThird<T_DOUBLE, T> {
static void apply(T bar) {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
public:
template <AllowedTypes type>
void add_one_third( double bar ) const {
AddOneThird<type, double>::apply(bar);
}
};
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: incomplete type ‘foo_class::AddOneThird<(foo_class::AllowedTypes)1u
// a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
With full specialization of a (friend) class:
#include <iostream>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
// if needed
// template<AllowedTypes> friend struct AddOneThird;
public:
template <AllowedTypes type> void add_one_third( double bar ) const;
};
template <foo_class::AllowedTypes>
struct AddOneThird;
template <>
struct AddOneThird<foo_class::T_DOUBLE> {
static void apply(double bar) {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
template <foo_class::AllowedTypes type>
void foo_class::add_one_third( double bar) const {
AddOneThird<type>::apply(bar);
}
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: incomplete type ‘AddOneThird<(foo_class::AllowedTypes)1u>’ used
// in nested name specifier
//a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
Utilizing C++11 or boost::enable_if:
#include <iostream>
#include <type_traits>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
template <AllowedTypes type>
typename std::enable_if<type == T_DOUBLE>::type
add_one_third( double bar ) const {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: no matching function for call to ‘foo_class::add_one_third(double)’
//a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
From Herb Sutter
It's a lot less intuitive to specialize function templates. For one thing, you can't partially specialize them -- pretty much just because the language says you can't.[2] For another thing, function template specializations don't overload. This means that any specializations you write will not affect which template gets used, which runs counter to what most people would intuitively expect. After all, if you had written a nontemplate function with the identical signature instead of a function template specialization, the nontemplate function would always be selected because it's always considered to be a better match than a template.
If you're writing a function template, prefer to write it as a single function template that should never be specialized or overloaded, and implement the function template entirely in terms of a class template. This is the proverbial level of indirection that steers you well clear of the limitations and dark corners of function templates. This way, programmers using your template will be able to partially specialize and explicitly specialize the class template to their heart's content without affecting the expected operation of the function template. This avoids both the limitation that function templates can't be partially specialized, and the sometimes surprising effect that function template specializations don't overload. Problem solved.
Your enum type sizeof is not 0, change that to 4 at least. Otherwise this will not work. A enum element size is not 0.
Without that everything runs
#include <iostream>
struct foo_class
{
enum AllowedTypes { DOG, CAT };
template <AllowedTypes type>
void add_one_third( double bar ) const
{
std::cout << "YES" << std::endl;
}
};
template<>
void foo_class::add_one_third<foo_class::DOG>( double bar ) const
{
std::cout << "DOG specialization: " << bar + 1./3. << std::endl;
}
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.add_one_third<foo_class::DOG>(3.0); // should succeed
// Compilation fails with or without the following line:
//a.add_one_third<foo_class::CAT>(3.0); // should fail at compile-time
return 0;
}
The main difference between the enum case and the referenced question using a typename parameter is that the default definition will be compiled for any use. So, a working solution is as simple as modifying the BOOST_STATIC_ASSERT condition to check allowed enum values.
#include <iostream>
#include <stdexcept>
#include <boost/static_assert.hpp>
// CLASS HEADER FILE:
struct foo_class
{
enum AllowedTypes { DOG, CAT, MOUSE };
template <AllowedTypes type>
void give_bath() const
{
// compile fails if ever attempting to use this function with CAT parameter.
BOOST_STATIC_ASSERT_MSG( (type==DOG) || (type==MOUSE) , "enum type not supported.");
throw std::runtime_error("Unexpected. Above list inconsistent with specializations.");
}
};
// CLASS SOURCE FILE
template<>
void foo_class::give_bath<foo_class::DOG>() const
{
std::cout << "DOG is bathed." << std::endl;
}
template<>
void foo_class::give_bath<foo_class::MOUSE>() const
{
std::cout << "MOUSE is bathed." << std::endl;
}
// USER SOURCE FILE
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.give_bath<foo_class::DOG>(); //success
a.give_bath<foo_class::MOUSE>(); // success
// Compilation fails with the following line:
//a.give_bath<foo_class::CAT>(); // fails at compile-time as intended.
return 0;
}
Of course, the whole design smells bad and could likely be handled more elegantly with AllowedTypes being a struct/class with inherited specializations. But this gets to the question at hand.

How to disambiguate function templates that differ only by return type?

I have noticed that there is an asymmetry between the signature used to distinguish unique template functions, and the signature used to distinguish unique functions (including those instantiated from template functions).
In particular, template functions that differ only by return type are considered to be unique, whereas functions that differ only by return type are considered to be redundant.
Therefore, I have a corresponding question about how to disambiguate between function templates that differ only by return type, at the point of instantiation:
#include <iostream>
template<typename T>
long foo(T)
{
std::cout << "long" << std::endl;
return 0;
}
template<typename T>
char foo(T)
{
std::cout << "char" << std::endl;
return '\0';
}
int main()
{
double d = 0.0;
long n = foo(d); // <- Ambiguous: How to specify the template function to use?
}
In the above code, the instantiation of the template function foo is ambiguous precisely because of the asymmetry I've just mentioned. The presence of the two template function definitions is legal, but the instantiation is illegal, even though the return type is specified in the same line of code.
I am asking this question purely for theoretical learning purposes. Perhaps this code construct, in real life, would be a sign of poor design. Perhaps it would never arise in real life. Also, I can envision different ways of overcoming this issue by changing the template definitions (or by making other changes).
However, I would nonetheless like to know if, keeping the template definitions unchanged, it is possible to disambiguate between these two template functions at the point of instantiation.
When using templates you can actually disambiguate the two different overloads. It ain't pretty but works:
long n = static_cast<long(*)(double)>(&foo)(d);
If you really need to have two function templates having the same names, same list of parameters, but different return types, you have no choice but differentiate the two by making the return type a template parameter:
template <typename R, typename T>
R foo(T);
IIRC there is partial function template specialization in C++11, although I could not find anything about it in the standard. If there is, this should work:
//partial function template specializations: C++11 only!
template <typename T>
long foo<long, T>(T)
{
std::cout << "long" << std::endl;
return 0;
}
template<typename T>
char foo<char, T>(T)
{
std::cout << "char" << std::endl;
return '\0';
}
Or else, in C++03:
template <typename R, typename T>
struct FooImpl;
template <typename T>
struct FooImpl<long, T>
{
static long doIt(T)
{
std::cout << "long" << std::endl;
return 0;
}
};
template <typename T>
struct FooImpl<char, T>
{
static char doIt(T)
{
std::cout << "char" << std::endl;
return '\0';
}
};
template <typename R, typename T>
R foo(T t)
{
return FooImpl<R, T>::doIt(t);
}
In both cases, your main would look like this:
int main()
{
double d = 0.0;
long n = foo<long>(d); // specify the return type only
auto c = foo<char>(n);
}

Do template specializations require template<> syntax?

I have a visitor class resembling this:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Clearly, operator()(bool b) is intended to be a specialization of the preceding template function.
However, it doesn't have the template<> syntax that I'm used to seeing before it, declaring this as a template specialization. But it does compile.
Is this safe? Is this correct?
Your code is not a template specialization, but rather a non-templated function. There are some differences there. The non-templated operator() will take precedence over a templated version (for an exact match, but type conversions will not take place there) but you can still force the templated function to be called:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
In your code there is not much of a difference, but if your code needs to pass the template parameter type it will get funnier:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}
What you have here is function overloading; to obtain template specialization, you indeed need the template <> syntax. However, you should be aware that these two approaches, even if they may seem identical, are subtly different, and even the compiler might get lost when choosing the right function to call. Listing all the possible cases would be a little too long for this answer, but you might want to check Herb Sutter GoTW #49 on the subject.
Oh, it'll compile. It just won't be a template function. You'll have a regular non-template function instead of a template specialization.
It's safe, and actually likely what you want as well. The Visitor pattern is normally implemented by overloading. Specializing function templates isn't really a good idea anyway.
What you did is not template serialization, but function overloading. It is safe.
P.S. It's difficult to say whether it's correct or not, without knowing what you're trying to achieve. Keep in mind that no matter is it template or overloaded function, your operator will be chosen in compile time. If you need to run-time dispatch, you need polymorphism, not overloading. Well, you probably know it anyway; just in case.
You have
void operator()(bool b) that is non
templated function
template< typename T > void
operator()(T t) which is a separate
base template that overloads the
above
You could have a full specialization of the second one as in template<> void operator(int i) which would only be considered when void operator()(bool b) did not match.
The specialization of base template is used to select which of the base template methods to call. However in your case you have a non-templated method that will get considered first.
The article Why Not Specialize Function Templates? gives quite good explanation of how the method is selected.
In sumary:
Non template functions are
considered first (this is your plain
operator()(bool) above)
Function base templates get checked
second (this is your templated
function), the most specialized base-template is selected and then if it has specialization for the exact types that specialization is used otherwise the base template is used with 'the correct' types (see explanation in the article)
Example:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
You get calls to:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called