C++ Primer 5th Edition has a snippet of advice at the end of chapter 16.3 (a chapter discussing function template overloading):
Declare every function in an overload set before you define any of the
functions. That way you don’t have to worry whether the compiler will
instantiate a call before it sees the function you intended to call.
So is this telling me that in choosing the candidate and viable functions during overload resolution it is possible the compiler might instantiate a function template that isn't chosen in the end? I tried to see whether this might actually happen:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <typename T> void test(T*) { }
int main(){
int *q = nullptr;
test(q); //test(T*) should be the best match
}
This program would throw a compiler error if test(T const &) was instantiated in any form, except the program compiles fine as expected. So what kind of compilation mishap is that tip trying to guard me from? When would it ever instantiate a function before it saw the function I was trying to call?
The author is warning you of this:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
int main(){
int *q = nullptr;
test(q); //test(T*) will not be matched.
}
template <typename T> void test(T*)
{
}
And these:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <> void test<int>(int const &);
void test(int *);
int main(){
int *q = nullptr;
test(q); //test(int*) should be the best match
int a;
test(a); // test<int>(int const&) should be the best match
}
template <> void test<int>(int const &)
{
}
void test(int *)
{
}
If you don't provide declarations of
template <> void test<int>(int const &);
void test(int *);
before main, they won't be matched in main.
I've seen plenty of SO questions that is some variation of
template<class T, class... Ts>
T sum(T t, Ts... ts) { return t + sum(ts...); }
// ^ |
// |--------------------------------
// only one visible in
// definition context
template<class T>
T sum(T t) { return t; }
int main() {
sum(1, 2); // doesn't compile
}
(The return type isn't perfect, but you get the idea.)
And then people are surprised when it doesn't compile.
Or, even more fun,
template<class T> void f(T t) { f((int)t); }
void f(int) { /*...*/ }
int main() {
f(1L); // infinite recursion
}
Related
I have something similar to this (stripped down example to the relevant points)
struct Foo
{
template <typename T>
constexpr std::enable_if<someTrait<T>::value ,T>::type& get() const { return something(); }
template <typename T>
std::enable_if<someOtherTrait<T>::value ,T>::type& get() { return somethingDifferent(); }
class Nested
{
public:
template <typename T>
T& get() { return foo.get<T>(); }
private:
Foo& foo;
}
}
e.g. Foo::get evaluates to a const constexpr function or something completely non-const depending on the template type.
Now I want to be able to do this
class Bar : public Foo::Nested
{
void nonConstFn()
{
auto& a = get<TypeA>();
//...
}
void constFn() const // <===== Won't compile
{
auto& a = get<TypeA>();
//...
}
}
It's obvious that Bar::constFn won't compile as it calls the non-const function Foo::Nested::get<TypeA> – even if TypeA would satisfy someTrait and call the const function constexpr Foo::get<TypeA>() const again in the end.
Leaving the constexpr aside for now, how do I propagate the constness of the called function in my nested class' function template? I tried simply overloading it with a const and non-const version of Nested::get which solves it for clang on macOS but fails with MSVC in Visual Studio 2015 on Windows, which is unfortunately a required build target.
Note that the original example contains a lot more than just two versions of Foo::get so I'd like to avoid repeating all versions in Foo::Nested but forward it with one or two function templates if possible
Edit: I tried the proposal to use
template <typename T>
constexpr auto get() const -> decltype(foo.get<T>()) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> decltype(foo.get<T>()) { return foo.get<T>(); }
on godbolt.org which seems to compile fine for current MSVC versions but fails with Visual Studio 2015 MSVC 19.0, so this is no option
First of you need enable_if::type for the SFINAE to work.
To get to your question you need to overload Nested::get:
#include <type_traits>
struct Foo
{
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const
{ return something(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get()
{ return somethingDifferent(); }
int& something() const;
float& somethingDifferent();
class Nested
{
public:
Nested();
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const { return foo.get<T>(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get() { return foo.get<T>(); }
private:
Foo& foo;
};
};
class Bar : public Foo::Nested
{
void nonConstFn()
{
[[maybe_unused]] auto& a = get<int>();
[[maybe_unused]] auto& b = get<float>();
}
void constFn() const
{
[[maybe_unused]] auto& a = get<int>();
}
};
You need const and non-const overload in Nested, you might avoid to repeat all overload/SFINAE with another (simple) SFINAE:
class Nested
{
Foo& foo; // Should be declared before the decltype usage
public:
Nested();
template <typename T>
constexpr auto get() const -> (decltype(foo.get<T>())) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> (decltype(foo.get<T>())) { return foo.get<T>(); }
};
Consider the following problem, which is meaningless but proposes a solution to yours. You have a class with two functions and an invoker for them
class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}
If you do A().invoke(), you will get foo obviously. If you want to force to execute the const type function, how do you achieve that? OK, you make the following change
A::invoke() { const_cast<const A*>(this)->foo(); } and that's it.
For example, given the following code
class A {
public:
double operator()(double foo) {
return foo;
}
};
class B {
public:
double operator()(double foo, int bar) {
return foo + bar;
}
};
I want to write two versions of fun, one that works with objects with A's signature and another one that works with objects with B's signature:
template <typename F, typename T>
T fun(F f, T t) {
return f(t);
}
template <typename F, typename T>
T fun(F f, T t) {
return f(t, 2);
}
And I expect this behavior
A a();
B b();
fun(a, 4.0); // I want this to be 4.0
fun(b, 4.0); // I want this to be 6.0
Of course the previous example throws a template redefinition error at compile time.
If B is a function instead, I can rewrite fun to be something like this:
template <typename T>
T fun(T (f)(T, int), T t) {
return f(t, 2);
}
But I want fun to work with both, functions and callable objects. Using std::bind or std::function maybe would solve the problem, but I'm using C++98 and those were introduced in C++11.
Here's a solution modified from this question to accommodate void-returning functions. The solution is simply to use sizeof(possibly-void-expression, 1).
#include <cstdlib>
#include <iostream>
// like std::declval in c++11
template <typename T>
T& decl_val();
// just use the type and ignore the value.
template <std::size_t, typename T = void>
struct ignore_value {typedef T type;};
// This is basic expression-based SFINAE.
// If the expression inside sizeof() is invalid, substitution fails.
// The expression, when valid, is always of type int,
// thanks to the comma operator.
// The expression is valid if an F is callable with specified parameters.
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1),1), void>::type
call(F f)
{
f(1);
}
// Same, with different parameters passed to an F.
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1,1),1), void>::type
call(F f)
{
f(1, 2);
}
void func1(int) { std::cout << "func1\n"; }
void func2(int,int) { std::cout << "func2\n"; }
struct A
{
void operator()(int){ std::cout << "A\n"; }
};
struct B
{
void operator()(int, int){ std::cout << "B\n"; }
};
struct C
{
void operator()(int){ std::cout << "C1\n"; }
void operator()(int, int){ std::cout << "C2\n"; }
};
int main()
{
call(func1);
call(func2);
call(A());
call(B());
// call(C()); // ambiguous
}
Checked with gcc and clang in c++98 mode.
I'm new to C++ and would like to get some help with fixing the following template function code without removing the function fl()
template<type T>
class Test
{
int f1(T* x);
};
template< T>
int Test::f1(T* x)
{
return 5:
};
You have numerous syntax errors, but I guess your main issue is you need Test<T>::f1 instead of Test::f1:
//typename, not type
template<typename T>
class Test
{
int f1(T* x);
};
// forgot typename
template<typename T>
int Test<T>::f1(T* x)
//need ^^^
{
return 5;
}
//^ no semicolon
The correct syntax would be
template<typename T>
class Test
{
int f1(T* x);
};
template<typename T>
int Test<T>::f1(T* x)
{
return 5;
};
Note the keyword specifying the template argument T is either typename or class
I want to automatically choose the right pointer-to-member among overloaded ones based on the "type" of the member, by removing specializations that accept unconcerned members (via enable_if).
I have the following code:
class test;
enum Type
{
INT_1,
FLOAT_1,
UINT_1,
CHAR_1,
BOOL_1,
INT_2,
FLOAT_2,
UINT_2,
CHAR_2,
BOOL_2
};
template<typename T, Type Et, typename func> struct SetterOk { static const bool value = false; };
template<typename T> struct SetterOk<T,INT_1,void (T::*)(int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_1,void (T::*)(float)> { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_1,void (T::*)(unsigned int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_1,void (T::*)(char)> { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_1,void (T::*)(bool)> { static const bool value = true; };
template<typename T> struct SetterOk<T,INT_2,void (T::*)(int,int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_2,void (T::*)(float,float)> { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_2,void (T::*)(unsigned int, unsigned int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_2,void (T::*)(char,char)> { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_2,void (T::*)(bool,bool)> { static const bool value = true; };
template <bool, class T = void> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template<typename T, Type Et>
struct Helper
{
template<typename U>
static void func(U method, typename enable_if<SetterOk<T,Et,U>::value>::type* dummy = 0)
{
}
};
class test
{
public:
void init()
{
Helper<test,INT_2>::func(&test::set);
}
void set2(int);
void set(int);
void set(int,int);
void set(float,float);
};
int main()
{
test t;
t.init();
return 0;
}
I'm expecting it to choose the right function between all possible. The problem is that the compiler says "cannot deduce template argument as function argument is ambiguous".
It seems I don't know how to use enable_if, because if so the compiler would only allow the specialization if the specified function has the right type...
Note that I want to have C++03 solutions (if possible) - my code must compile on some old compilers.
Thanks in advance
You can never refer to an overloaded function without disambiguating it (means: static_casting it to the correct type). When you instantiate Helper::func the type of the function argument cannot be known without ever disambiguating it.
The reason it doesn't compile is quite simply that there are several different overloaded functions and it doesn't know which one you mean. Granted, only one of these (void set(int,int)) would actually compile, given the specialization Helper<test,INT_2>. However, this is not enough for the compiler to go on.
One way of getting this to compile would be to explicitly cast &test::set to the appropriate type:
Helper<test,INT_2>::func(static_cast<void (test::*)(int,int)>(&test::set));
Another way would be to use explicit template specialization:
Helper<test,INT_2>::func<void (test::*)(int,int)>((&test::set));
Either way, you need to let the compiler know which of the set functions you are trying to refer to.
EDIT:
As I understand it, you want to be able to deduce, from the use of a Type, which function type should be used. The following alternative achieves this:
template<typename T, Type Et> struct SetterOK{};
template<typename T> struct SetterOK<T,INT_1> {typedef void (T::*setter_type)(int);};
template<typename T> struct SetterOK<T,FLOAT_1> {typedef void (T::*setter_type) (float);};
// ...
template<typename T> struct SetterOK<T,INT_2> {typedef void (T::*setter_type)(int,int);};
// ....
template<typename T, Type Et>
struct Helper
{
template<typename U>
static void func(U method)
{
}
};
class test
{
public:
void init()
{
Helper<test,INT_2>::func<SetterOK<test,INT_2>::setter_type >(&test::set);
}
void set2(int);
void set(int);
void set(int,int);
void set(float,float);
};
int main()
{
test t;
t.init();
return 0;
}
ADDITIONAL EDIT:
A thought just occurred to me. In this special case which you've done, where U is SetterOK::setter_type, things can be simplified further by completely removing the template arguments for func:
static void func(typename SetterOK<T,Et>::setter_type method)
{
}
This would make the init method a simpler:
void init()
{
Helper<test,INT_2>::func(&test::set);
}
I know the language specification forbids partial specialization of function template.
I would like to know the rationale why it forbids it? Are they not useful?
template<typename T, typename U> void f() {} //allowed!
template<> void f<int, char>() {} //allowed!
template<typename T> void f<char, T>() {} //not allowed!
template<typename T> void f<T, int>() {} //not allowed!
AFAIK that's changed in C++0x.
I guess it was just an oversight (considering that you can always get the partial specialization effect with more verbose code, by placing the function as a static member of a class).
You might look up the relevant DR (Defect Report), if there is one.
EDIT: checking this, I find that others have also believed that, but no-one is able to find any such support in the draft standard. This SO thread seems to indicate that partial specialization of function templates is not supported in C++0x.
EDIT 2: just an example of what I meant by "placing the function as a static member of a class":
#include <iostream>
using namespace std;
// template<typename T, typename U> void f() {} //allowed!
// template<> void f<int, char>() {} //allowed!
// template<typename T> void f<char, T>() {} //not allowed!
// template<typename T> void f<T, int>() {} //not allowed!
void say( char const s[] ) { std::cout << s << std::endl; }
namespace detail {
template< class T, class U >
struct F {
static void impl() { say( "1. primary template" ); }
};
template<>
struct F<int, char> {
static void impl() { say( "2. <int, char> explicit specialization" ); }
};
template< class T >
struct F< char, T > {
static void impl() { say( "3. <char, T> partial specialization" ); }
};
template< class T >
struct F< T, int > {
static void impl() { say( "4. <T, int> partial specialization" ); }
};
} // namespace detail
template< class T, class U >
void f() { detail::F<T, U>::impl(); }
int main() {
f<char const*, double>(); // 1
f<int, char>(); // 2
f<char, double>(); // 3
f<double, int>(); // 4
}
Well, you really can't do partial function/method specialization however you can do overloading.
template <typename T, typename U>
T fun(U pObj){...}
// acts like partial specialization <T, int> AFAIK
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...}
It is the way but I do not know if it satisfy you.
In general, it's not recommended to specialize function templates at all, because of troubles with overloading. Here's a good article from the C/C++ Users Journal: http://www.gotw.ca/publications/mill17.htm
And it contains an honest answer to your question:
For one thing, you can't partially specialize them -- pretty much just because the language says you can't.
Since you can partially specialize classes, you can use a functor:
#include <iostream>
template <typename dtype, int k> struct fun
{
int operator()()
{
return k;
}
};
template <typename dtype> struct fun <dtype, 0>
{
int operator()()
{
return 42;
}
};
int main ( int argc , char * argv[] )
{
std::cout << fun<float, 5>()() << std::endl;
std::cout << fun<float, 0>()() << std::endl;
}