The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).
Related
Here's a minimal example:
#include <iostream>
#include <type_traits>
template <typename T>
struct Foo {
typedef typename std::decay<T>::type U;
const U s;
Foo(const T& val): s(val) {}
};
template <typename T>
Foo<T> make_foo(const T& val) {
return Foo<T>(val);
}
int main() {
make_foo("foo");
}
I expect Foo::s (or U) to be const-ed, but the compiler error I'm getting (on Ubuntu WSL g++ 7.4.0) is
bar.cpp: In instantiation of ‘Foo<T>::Foo(const T&) [with T = char [4]]’:
bar.cpp:14:12: required from ‘Foo<T> make_foo(const T&) [with T = char [4]]’
bar.cpp:18:19: required from here
bar.cpp:9:28: error: invalid conversion from ‘const char*’ to ‘Foo<char [4]>::U {aka char*}’ [-fpermissive]
Foo(const T& val): s(val) {}
^
which obviously means that neither U or Foo::s is a const char*. Thoughts?
EDIT:
For anyone running into this problem, the solution is exactly as StoryTeller points out in his post below. In other words, the const I had in make_foo(const T& val) in the parameter signature was stripping the const from the type parameter and making T evaluate to char [4]. And for some reason, I couldn't even grasp putting a const in the template angle brackets of each instance of Foo<...> (the return type and the expression returned):
#include <iostream>
#include <type_traits>
template <typename T>
struct Foo {
static_assert(std::is_same<T, const char[4]>::value);
typedef typename std::decay<T>::type U;
static_assert(std::is_same<U, const char*>::value);
U s;
Foo(const T& val): s(val) {}
};
template <typename T>
Foo<const T> make_foo(const T& val) {
static_assert(std::is_same<T, char[4]>::value);
return Foo<const T>(val);
}
int main() {
make_foo("foo");
}
Also, as chris pointed out as well, it's nice to spam static_assert and std::is_same to make dealing with templates in combination with const a bit more sane.
make_foo accepts by a const T &, and you pass in a constant array of 4 characters (that's what string literals are). Template argument deduction must therefore match a const char (&)[4] against the const T &. And since the const is specified in the parameter type, that leaves T as char[4]. The const qualifier is "consumed" by the function parameter.
So when you instantiated Foo<T>, you did so with char[4]. That type will decay to a char*, not a const char*. Adding const on top of it will only produce a char * const.
If you wish to preserve the const-ness of T, then amend your return statement (and type) to be
return Foo<const T>(val);
Boost's <boost/any.hpp> has:
template<typename ValueType>
ValueType any_cast(any & operand);
template<typename ValueType>
inline ValueType any_cast(const any & operand);
(among other variants.) Shouldn't this combination cause ambiguity in calls such as boost::any_cast<int>(my_any); ?
I'm asking because if I write this program:
#include <boost/any.hpp>
#include <iostream>
template<typename ValueType>
ValueType any_cast(boost::any & operand)
{
return boost::any_cast<ValueType>(operand);
}
int main()
{
int x = 123;
boost::any my_any(x);
std::cout << "my_any = " << any_cast<int>(my_any) << "\n";
return 0;
}
I do get a complaint about ambiguity:
g++ -std=c++14 -O3 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:14:57: error: call of overloaded 'any_cast(boost::any&)' is ambiguous
std::cout << "my_any = " << any_cast<int>(my_any) << "\n";
^
main.cpp:5:11: note: candidate: ValueType any_cast(boost::any&) [with ValueType = int]
ValueType any_cast(boost::any & operand)
^~~~~~~~
In file included from main.cpp:1:0:
/usr/local/include/boost/any.hpp:281:22: note: candidate: ValueType boost::any_cast(const boost::any&) [with ValueType = int]
inline ValueType any_cast(const any & operand)
^~~~~~~~
/usr/local/include/boost/any.hpp:258:15: note: candidate: ValueType boost::any_cast(boost::any&) [with ValueType = int]
ValueType any_cast(any & operand)
^~~~~~~~
Why would the calls be ambiguous? The way you call the function the any argument is an lvalue. Thus, the any argument will either be const-qualified in which case the second overload is the only potential match or it is not const-qualified in which case the first overload is the better match (there is no conversion needed while the second overload would need a conversion from any& to any const&). If you call the function with a temporary any, it could bind to an rvalue overload (i.e., taking any&&) or, if that doesn't exist, it can bind to the const-qualified overload but not the non-const-qualified overload, again, not causing any ambiguity.
Actually, there is something interesting happening here: without the overload in the global namespace the function using the explicit template argument cannot be used! However, as soon as any function template is present, even a non-matching one, it can be used! Here is an example:
namespace foo {
struct bar {};
template <typename T> void bar_cast(bar&) {}
template <typename T> void bar_cast(bar const&) {}
template <typename T> void bar_cast(bar&&) {}
}
struct whatever;
template <typename T> void bar_cast(whatever);
int main()
{
foo::bar b;
bar_cast<int>(b);
}
I kind of need help! I want to define a template method for my class to access its private fields. Here is my code:
#include <string>
#include <vector>
using namespace std;
class ex
{
public:
ex(string pegah_,int amin_):pegah(pegah_),amin(amin_){}
template<typename T>
T get_field(){
if(is_same<T,string>::value)
return pegah;
else if(is_same<T,int> ::value)
return amin;
}
private:
string pegah;
int amin;
};
int main(void)
{
string i = "salam";
int o=10;
ex y(i,o);
y.get_field<string>();
}
as you see I want to use just one function. But I keep getting this error:
test.cpp: In instantiation of ‘T ex::get_field() [with T = std::basic_string<char>]’:
test.cpp:30:21: required from here
test.cpp:15:8: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
return amin;
^
In file included from /usr/include/c++/4.8/string:52:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/basic_string.h:490:7: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
can anyone help?
Instead you could lay your code out like this:
template<typename T> T get_field();
// outside the class:
template<> inline int ex::get_field<int>() { return amin; }
template<> inline string ex::get_field<string>() { return pegah; }
As you have it now, all branches of the if..else must compile.
Basically you have three options to do it.
First using explicit specialization of template member function.
class Foo {
public:
template <typename T>
T get () const;
private:
std::string str {"XXX"};
int value {42};
};
template <>
inline std::string Foo::get () const {
return str;
}
template <>
inline int Foo::get () const {
return value;
}
Second one is to use helper function with different parameters type.
class Foo2 {
public:
template <typename T>
T get () const {
return get_helper (typename std::is_same<T, std::string>::type {});
}
private:
std::string get_helper (std::true_type) const {
return str;
}
int get_helper (std::false_type) const {
return value;
}
private:
std::string str {"YYY"};
int value {44};
};
Third option is to use SFINAE.
class Foo3 {
public:
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type get () const {
return str;
}
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, T>::type get () const {
return value;
}
private:
std::string str {"ZZZ"};
int value {45};
};
and usage would be like:
template <typename T>
void show (T v) {
std::cout << v << std::endl;
}
Foo f1;
show (f1.get<std::string> ());
show (f1.get<int> ());
Foo2 f2;
show (f2.get<std::string> ());
show (f2.get<int> ());
Foo3 f3;
show (f3.get<std::string> ());
show (f3.get<int> ());
Second option is helpful when you want to distinguish between two types. If you have more getters, then probably you will need to use first or third option.
I think it is better you define a getter and setter for each field. That is a better approach. It's easier to read and to understand and you achieve the same as with the template technique.
Explanation of your code:
It does not compile because of type checking. Template functions are generated when used in C++11. You use it with template parameter string so the function is generated. The problem is that you generate a function that returns T as a string, but you have code in your function that returns int (variable amin). Generate the function in your mind like so for T equals string:
string get_field(){
if(is_same<string,string>::value)
return pegah; // OK
else if(is_same<string,int> ::value)
return amin; // NOT OK, amin is of type int
}
One solution is that of M.M, it's called specialization. You specialize a template for (a) specific argument(s). And there are also other answers coming up.
I do not recommend that, because you finally do nothing else but generating getter functions for each variable in a specialized template. You could as well just have written:
string get_pegah(){ return pegah; }
int get_amin() { return amin; }
Easier to read, to maintain and straight forward. And more efficient I think.
as you see I want to use just one function
You don't really. You either call get_field<string> or get_field<int> and when called the appropriate function would be generated; either with T=string, T=int or both (depending on your use case). Though as you have learned by now, it's an error to do so in that case.
What you probably meant was that you want to have one function definition to do what you want. I don't think that is possible.
The following code is a minimum working (or perhaps non-working) example.
What it does is basically encapsulates a bunch of std::map structures as private members in a base class. To avoid writing a lot of setters and getters, they are implemented as template functions.
// test.cpp
#include <map>
#include <iostream>
enum class E0
{
F0, F1, F2,
};
The declaration of the base class.
using std::map;
class P_base
{
private:
map<E0, int> m_imap;
// ...
// ... Other std::map members with different key types and value types.
public:
map<E0, int> & imap;
// ...
// ... Other std::map references.
P_base() : imap(m_imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
m[k] = v;
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(m.at(k))
{
return m.at(k);
}
};
class P : private P_base
{
public:
decltype(P_base::imap) & imap;
P() : P_base(), imap(P_base::imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
P_base::set(m, k, v);
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(P_base::access_to_map(m, k))
{
return P_base::access_to_map(m, k);
}
};
main
int main(int argc, const char * argv[])
{
using std::cout;
using std::endl;
P op;
op.set(op.imap, E0::F0, 100);
op.set(op.imap, E0::F1, 101);
op.set(op.imap, E0::F2, 102);
cout << op.access_to_map(op.imap, E0::F1) << endl;
}
$ clang++ -std=c++11 test.cpp && ./a.out
101
But if I compile it with intel compiler (icpc version 15.0.3 (gcc version 5.1.0 compatibility)), the compiler gives me this error message (which I don't undertand at all, especially when clang will compile the code):
$ icpc -std=c++ test.cpp && ./a.out
test.cpp(67): error: no instance of function template "P::access_to_map" matches the argument list
argument types are: (std::__1::map<E0, int, std::__1::less<E0>, std::__1::allocator<std::__1::pair<const E0, int>>>, E0)
object type is: P
cout << op.access_to_map(op.imap, E0::F1) << endl;
And it also confuses me by not complaining about the set function.
Does anyone have any idea what is going on here?
Note: My answer applies to g++ - hopefully it's the same as icc.
Here is a smaller test case:
struct Base
{
int func(int t) { return t; }
};
struct Der : Base
{
template<typename T>
auto f(T t) -> decltype(Base::func(t))
{
return t;
}
};
int main(){ Der d; d.f(5); }
The error is:
mcv.cc: In function 'int main()':
mcv.cc:16:25: error: no matching function for call to 'Der::f(int)'
int main(){ Der d; d.f(5); }
^
mcv.cc:16:25: note: candidate is:
mcv.cc:9:7: note: template<class T> decltype (t->Base::func()) Der::f(T)
auto f(T t) -> decltype(Base::func(t))
^
mcv.cc:9:7: note: template argument deduction/substitution failed:
mcv.cc: In substitution of 'template<class T> decltype (t->Base::func()) Der::f(T) [with T = int]':
mcv.cc:16:25: required from here
mcv.cc:9:38: error: cannot call member function 'int Base::func(int)' without object
auto f(T t) -> decltype(Base::func(t))
This can be fixed by changing decltype(Base::func(t)) to decltype(this->Base::func(t)). A corresponding fix fixes your code sample, for me.
Apparently, the compiler doesn't consider that Base::func(t) should be called with *this as hidden argument. I don't know if this is a g++ bug, or if clang is going beyond the call of duty.
Note that in C++14, since the function has a single return statement, the trailing return type can be omitted entirely:
template<typename T>
auto f(T t)
{
return t;
}
I cannot figure out why this segment gives unresolved overloaded function error (gcc version 4.3.4 (Debian 4.3.4-6)):
#include <algorithm>
#include <boost/function.hpp>
// this does not work
int main1()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
// this does not work
int main2() {
typedef boost::function2<const int&, const int&, const int&> max;
max m(static_cast<max>(&std::max<int>));
}
can you help me, thanks
test.cpp: In function âint main()â:
test.cpp:7: error: no matching function for call to âboost::function2<const int&, const int&, const int&>::function2(<unresolved overloaded function type>)â
/usr/include/boost/function/function_template.hpp:747: note: candidates are: boost::function2<R, T1, T2>::function2(const boost::function2<R, T1, T2>&) [with R = const int&, T0 = const int&\
, T1 = const int&]
/usr/include/boost/function/function_template.hpp:739: note: boost::function2<R, T1, T2>::function2(boost::function2<R, T1, T2>::clear_type*) [with R = const int&, T0 = cons\
t int&, T1 = const int&]
/usr/include/boost/function/function_template.hpp:707: note: boost::function2<R, T1, T2>::function2() [with R = const int&, T0 = const int&, T1 = const int&]
max/min is defined as
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
__glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
I have tried all sorts of template explicit instantiation but nothing seems to work. Same problem appears with g++ 4.1 but not with ICC
this works
#include <algorithm>
#include <boost/function.hpp>
namespace std_ {
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
}
int main()
{
typedef const int &T;
typedef boost::function<T(T,T)> min_;
//typedef const int&(*min_)(const int&, const int&);
min_ m(::std_::max<int>);
}
and this
#include <algorithm>
#include <boost/function.hpp>
int main()
{
//typedef const int &T;
//typedef boost::function<T(T,T)> min_;
typedef const int&(*min_)(const int&, const int&);
min_ m(::std::max<int>);
}
Update: this is a gcc bug that has been fixed in gcc >=4.4. bugzilla. Also, revised my answer with a reduced test case.
There are two components to this problem: the way boost::function adopts a function pointer and the gcc bug.
boost::function - There is something strange about the error message you listed in the question; there is no candidate constructor that accepts anything like a function address. Digging into the boost::function src, the relevant constructor is (leaving out the enable_if argument):
template<typename Functor>
function(Functor f) : base_type(f) {}
So boost::function doesn't help you out at all in specifying the type of a function pointer; if the function is overloaded the address must be cast to specify its type. If an overloaded function address is used, the above template can't be instantiated, and therefore the appropriate constructor doesn't show up in the error message.
gcc bug - If you look at the stl_algobase.h header again, you'll see there are two templates named max, a two param version and a one param version. This shouldn't be a problem with you code though, right? The term &max<int> should instantiate the single param version and take its address. However, that is not what happens. You can see the problem in the reduced (no header) test case:
template <class T>
const T& max(const T& x, const T& y){
return x > y ? x : y;
}
template <class T, class C>
const T& max(const T& x, const T& y, C comp){
return comp(x, y) ? y : x;
}
template <class R, class A0, class A1>
struct functor{
template <class F>
functor(F f) : f(f) {}
R (*f)(A0, A1);
};
int main(void){
functor<const int&, const int&, const int&> func(&max<int>);
return 0;
}
The above code results in a unresolved overloaded function type with gcc 4.3.4. The fix is either to remove the template <class T, class C> max(...){...} definition or add a static_cast<const int& (*)(const int&, const int&)>(...) around the function address. I'm guessing the problem has to do with incorrect application of partial explicit parameter specification, which is specified by the standard. It lets you leave out trailing template parameters to do things like specify a return value type and not the argument types. That is, the compiler instantiates both template when it should only instantiate the fully specified template. Its moot speculation though, since the bug has been fixed in gcc >= 4.4.
Since one shouldn't hack at stl_algobase.h ;) , the work around Vicente suggests is the correct one, namely cast the function pointer to the desired function pointer type const int& (*)(const int&, const int&). In your code, the cast doesn't work because, as GMan points out, you are casting to a boost::function<...>, which does nothing to resolve the function pointer ambiguity.
To critique the code, there's no reason to static_cast that. Consider all the cast is going to do is use the constructor of boost::function2 to make a new boost::function2, then it will be copy-constructed into m. Just construct directly into m:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function2<const int&, const int&, const int&> max;
max m(&std::max<int>);
}
Lastly, the preferred syntax of boost::function is:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
The n-ary specific classes are for older compiler support.
It seems to be a problem with the definition of the std::max template function with releases of gcc < 4.4
With gcc-4.4.0 and msvc Express9 it works.
The following works also for gcc-3.4 and gcc-4.3
int main1()
{
int res = std::max(1,2);
typedef boost::function<const int&(const int&, const int&)> max;
max m(static_cast<const int&(*)(const int&, const int&)>(std::max<int>));
return 0
}