What does this error message mean?
error: call of overloaded ‘setval(int)’ is ambiguous
huge.cpp:18: note: candidates are: void huge::setval(unsigned int)
huge.cpp:28: note: void huge::setval(const char*)
My code looks like this:
#include <iostream>
#define BYTES 8
using namespace std ;
class huge {
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
void setval(const char *);
};
void huge::setval(unsigned int t) {
for(int i = 0; i< BYTES ; i++) {
data[i] = t;
t = t >> 1;
}
}
void huge::setval(const char *s) {
for(int i = 0; i< BYTES ; i++)
data[i] = s[i];
}
int main() {
huge p;
p.setval(0);
return 0;
}
NathanOliver
168k28 gold badges280 silver badges387 bronze badges
asked Jan 12, 2011 at 17:54
3
The literal 0
has two meanings in C++.
On the one hand, it is an integer with the value 0.
On the other hand, it is a null-pointer constant.
As your setval
function can accept either an int
or a char*
, the compiler can not decide which overload you meant.
The easiest solution is to just cast the 0
to the right type.
Another option is to ensure the int
overload is preferred, for example by making the other one a template:
class huge
{
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
template <class T> void setval(const T *); // not implemented
template <> void setval(const char*);
};
answered Jan 12, 2011 at 19:47
6
The solution is very simple if we consider the type of the constant value, which should be «unsigned int» instead of «int».
Instead of:
setval(0)
Use:
setval(0u)
The suffix «u» tell the compiler this is a unsigned integer. Then, no conversion would be needed, and the call will be unambiguous.
answered Nov 28, 2011 at 14:27
Leonardo L.Leonardo L.
3062 silver badges5 bronze badges
1
replace p.setval(0);
with the following.
const unsigned int param = 0;
p.setval(param);
That way it knows for sure which type the constant 0 is.
answered Jan 12, 2011 at 17:58
Null SetNull Set
5,36224 silver badges37 bronze badges
Use
p.setval(static_cast<const char *>(0));
or
p.setval(static_cast<unsigned int>(0));
As indicated by the error, the type of 0
is int
. This can just as easily be cast to an unsigned int
or a const char *
. By making the cast manually, you are telling the compiler which overload you want.
answered Jan 12, 2011 at 17:58
EclipseEclipse
44.4k19 gold badges113 silver badges170 bronze badges
Cast the value so the compiler knows which function to call:
p.setval(static_cast<const char *>( 0 ));
Note, that you have a segmentation fault in your code after you get it to compile (depending on which function you really wanted to call).
answered Jan 12, 2011 at 17:58
Mark LoeserMark Loeser
17.3k2 gold badges30 silver badges34 bronze badges
That is ambiguous because a pointer is just an address, so an int
can also be treated as a pointer – 0 (an int
) can be converted to unsigned int
or char *
equally easily.
The short answer is to call p.setval()
with something that’s unambiguously one of the types it’s implemented for: unsigned int
or char *
. p.setval(0U)
, p.setval((unsigned int)0)
, and p.setval((char *)0)
will all compile.
It’s generally a good idea to stay out of this situation in the first place, though, by not defining overloaded functions with such similar types.
Adrian Mole
48.1k140 gold badges49 silver badges78 bronze badges
answered Jan 12, 2011 at 18:00
metamattmetamatt
13.5k7 gold badges45 silver badges56 bronze badges
2
Pre-requisite: Function Overloading in C++
Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading. Two or more functions are said to be overloaded if they differ in any of the following-
- The number of arguments.
- Order of arguments.
- Type of arguments.
In Function overloading, sometimes a situation can occur when the compiler is unable to choose between two correctly overloaded functions. This situation is said to be ambiguous.
Ambiguous statements are error-generating statements and the programs containing ambiguity will not compile. Automatic type conversions are the main cause of ambiguity. In C++, the type of argument that is used to call the function is converted into the type of parameters defined by the function.
Let’s understand ambiguity through a few examples.
Call of overloaded function is ambiguous
Example 1: Call of overloaded ‘test(char)’ is ambiguous
How this ambiguity occurs:
Below is the C++ program to demonstrate the ambiguity.
C++
#include <iostream>
using
namespace
std;
void
test(
float
f)
{
cout <<
"Overloaded Function with float "
<<
"parameter being called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with double "
<<
"parameter being called"
;
}
int
main()
{
test(
'a'
);
return
0;
}
Output:
prog.cpp: In function ‘int main()’:
prog.cpp:25:11: error: call of overloaded ‘test(char)’ is ambiguous
test(‘a’);
^
prog.cpp:8:6: note: candidate: void test(float)
void test(float f)
^
prog.cpp:15:6: note: candidate: void test(double)
void test(double d)
^
Why ambiguity occurs:
When there is no exact type match, the compiler looks for the closest match. The closest match for “test(‘a’);” will be “void test(int a)”, since it is not present, void test(double d) and void (float f)will cause ambiguity. Both are valid conversions. This confusion causes an error message to be displayed and prevents the program from compiling.
Note:
According to the C language specification, any integer type shorter than int, for example, bool, char, short are implicitly converted to int.
A char fits into an int without overflowing or losing precision, which explains the first code. But an int doesn’t fit into a char (overflow), double (lack of precision), or int* (incompatible type).
How to resolve ambiguity:
There are two ways to resolve this ambiguity:
- Typecast char to float.
- Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.
Solution 1: Typecast char to float
Below is the C++ program to demonstrate how typecasting char to float resolves the issue.
C++
#include <iostream>
using
namespace
std;
void
test(
float
f)
{
cout <<
"Overloaded Function with float "
<<
"parameter being called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with double "
<<
"parameter being called"
;
}
int
main()
{
test((
float
)(
'a'
));
return
0;
}
Output
Overloaded Function with float parameter being called
Solution 2: Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.
Below is the C++ program to demonstrate how adding an overloading function with an int type parameter can resolve the ambiguity in the above code.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with "
<<
"double type parameter called"
;
}
int
main()
{
test(
'a'
);
return
0;
}
Output
Overloaded Function with int type parameter called
Example 2: Call of overloaded ‘test(float)’ is ambiguous
How this ambiguity occurs:
Below is the C++ program to demonstrate what will happen in the scenario when the type of float value is used to call the overloaded function and there is no function with the float or double parameters.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test(2.5f);
return
0;
}
Output:
prog.cpp: In function ‘int main()’:
prog.cpp:25:12: error: call of overloaded ‘test(float)’ is ambiguous
test(2.5f);
^
prog.cpp:8:6: note: candidate: void test(int)
void test(int f)
^
prog.cpp:15:6: note: candidate: void test(long int)
void test(long d)
^
Why ambiguity occurs:
The above code will throw an error because the test(2.5f) function call will look for float function if not present it is only promoted to double, but there is no function definition with double or float type of parameter.
Unless explicitly specified all floating-point literals are automatically of type double in C++. In this ambiguity, the variable of a float type is implicitly converted to double type and if there is no overloaded function of float or double type and the function is called with a float value then the program will throw an error.
Note:
The float is converted to double under the following situations:
- The float is an argument to a function call, corresponding to a parameter type double in a function prototype.
- A binary operator has double and float as two argument types.
- A conditional operator has double and float as a second and third operand.
- The float value is cast to double.
- The float value is assigned to double.
How to resolve ambiguity:
There are two ways to resolve the ambiguity-
- Typecast float to int.
- Remove either one of the ambiguity generating functions int or long and add overloaded function with a double type parameter.
Solution 1: Typecast float to int
Below is the C++ program to demonstrate how typecasting float to int resolves the issue.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test((
int
)(2.5f));
return
0;
}
Output
Overloaded Function with int type parameter called
Solution 2: Remove either one of the ambiguity generating functions int or long and add overloaded function with a double type parameter.
Below is the C++ program to demonstrate how to resolve this ambiguity by adding an overloaded function with double type parameters.
C++
#include <iostream>
using
namespace
std;
void
test(
double
d)
{
cout <<
"Overloaded Function with "
<<
"double type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test(2.5f);
return
0;
}
Output
Overloaded Function with double type parameter called
Call of overloaded function with different number of arguments
Redefinition of ‘void test(int, int) function:
Let’s look at another ambiguity scenario where ambiguity occurs when it is two-parameter and one of the parameters has a default value set.
C++
#include <iostream>
using
namespace
std;
void
test(
int
i)
{
cout <<
"Overloaded function with "
<<
"one int parameter called "
<< endl;
cout << i;
}
void
test(
int
i,
int
j = 5)
{
int
sum;
sum = i + j;
cout <<
"Overloaded function with "
<<
"two int parameter called "
<< endl;
cout << sum;
}
int
main()
{
test(10, 11);
test(10);
return
0;
}
Output:
prog.cpp: In function ‘void test(int, int)’:
prog.cpp:17:6: error: redefinition of ‘void test(int, int)’
void test(int i, int j = 5)
^
prog.cpp:8:6: note: ‘void test(int, int)’ previously defined here
void test(int i, int j)
^
prog.cpp: In function ‘int main()’:
prog.cpp:35:10: error: too few arguments to function ‘void test(int, int)’
test(10);
^
prog.cpp:8:6: note: declared here
void test(int i, int j)
^
Why ambiguity occurs:
Here, in the unambiguous call statement test(10, 11) two arguments are specified, therefore there is no ambiguity. In the ambiguous call statement test(10), the compiler gets confused about whether to call the first function test() which takes one argument or to call the second test() function with two arguments out of which one is the default. This causes the program to throw an error.
How to resolve the ambiguity:
One solution to resolve the ambiguity is to remove the default value from the overloaded function with two int parameters. Below is the C++ program to demonstrate the above approach-
C++
#include <iostream>
using
namespace
std;
void
test(
int
i)
{
cout <<
"Overloaded function with "
<<
"one int parameter called "
<< endl;
cout << i << endl;
}
void
test(
int
i,
int
j)
{
int
sum;
sum = i + j;
cout <<
"Overloaded function with "
<<
"two int parameter called "
<< endl;
cout << sum << endl;
}
int
main()
{
test(10, 11);
test(10);
return
0;
}
Output
Overloaded function with two int parameter called 21 Overloaded function with one int parameter called 10
Time Complexity: O(1)
Auxiliary Space: O(1)
Problem:
You are trying to compile a C/C++ program but you see an error message like
srcmain.cpp:127:21: error: call of overloaded 'abs(uint32_t)' is ambiguous
that refers to a line like
long timedelta = abs(millis() - startTime);
Solution:
Cast the argument to abs()
to int
or another suitable type:
long timedelta = abs(((int)millis() - startTime));
That should fix the error.
The reason for the error message is that millis()
and startTime
are both unsigned integers (uint32_t
), hence their difference (millis() - startTime
) is also an uint32_t
. However it makes no sense to compute the abs()
of an unsigned integer since the absolute value of an absolute-value integer is always the same as the input argument.
Then, the compiler tries to cast the uint32_t
to any type that is compatible with abs()
, like int
, float
, double
, … but it doesn’t know which of those types is the correct one to cast it to.
By saying call of overloaded abs()
the compiler is trying to tell you that there are multBiple argument types with which you can call abs()
, including int
, float
, double
, … – a function with the same name but different argument types is called overloaded.
By saying is ambiguous
, the compiler is telling you that it doesn’t know which of those variants of abs()
it should call.
Note that the compiler does not know that all overloaded variants of abs()
fundamentally do the same thing, so it won’t just cast your uint32_t
into any arbitrary type. Also, there are tiny details in how the abs()
variants work – for example, float abs(float)
will do a different calculation compared to double abs(double)
since it computes with 32-bit floating point numbers (float
) as opposed to 64-bit floating point numbers (double
).
Hence, the compiler can’t just assume that they are all the same and it doesn’t matter which one it calls, even though they represent the same underlying mathematical operation
- Forum
- General C++ Programming
- Call of overloaded constructor is ambigu
Call of overloaded constructor is ambiguous
When I try to instantiate objects of class Foo in main() of foo.cpp, I keep getting errors about how the call to the overloaded constructor is ambiguous. The compiler seems to not be able to tell between a non-reference parameter input like int num
and a lreference parameter input like int &num
. It also seems to not be able to tell between a non-reference parameter input and a rreference parameter input like int &&num
. Why would this be? If the passed element is not any kind of reference, doesn’t it make a copy of the original element and then pass the copy? Passing by lreference would mean that a pointer to the original element is passed and that the user could manipulate the original element by manipulating the reference, right? Same goes with rreferences? Why is the compiler confused when I clearly sent it something that has to be moved from one place in memory to another without creating a copy?
Relevant error readout and code that I referenced are listed below:
compiler readout
|
|
foo.cpp
|
|
lvalue and rvalue reference parameters provide a means to overload functions on the value categories of their arguments.
Consider these two overloads of
f
:
|
|
An expression like
f(e)
calls the first overload when
e
is an lvalue expression; it calls the second overload when
e
is an rvalue expression.
This third overload of
f
does not care about the value category of
e
.
void f(int) {}
Mixing the three functions leads to ambiguity. Which function should be called when the argument is a rvalue?
Last edited on
So because the third overload does not care about the value category, is there a way to represent a non-reference value without causing ambiguity?
How could these not be ambiguous?
|
|
@dutch- I understand why it would cause ambiguity. See my question above your comment.
Then your question is senseless.
is there a way to represent a non-reference value without causing ambiguity?
References are not objects, and the type of an expression is never a reference. Given the declaration
int& x = y;
The type of the expression
x
is
int
.
What behavior do you want to see, and why do you think you want to see it?
In one of the constructors, I want a copied value to be passed in as a parameter that isn’t referencing the original value. int &x, for example, would pass a pointer to the callee that can then have its original value modified or assigned to some other value. int &&x would be an rvalue that doesn’t have its own assigned place in memory. Neither of these methods of passing some sort of value, from what I understand, are able to pass a value that is a copy of the original value but that can’t affect the original value if the parametrized value is assigned something new.
My above comment was not meant to imply that I never was asking about why the compiler found ambiguities. I was asking about that and @mbozzi clarified it for me. Then I had a question about how I would represent a parameratized value that would be a copy of another value that cannot be altered by the callee. A reference to a value WOULD be able to be alterted by the callee as the parameratized input is pointing to an already existing place in memory. Changing the data of that parameratized input would change what data was held at that same memory address.
Last edited on
If a copy is needed, just pass-by-value?
void f(int) {}
I think, the ambiguity is because you have overloaded constructors, if you just remove other two constructors (&),(&&), then you can achieve what you are saying.
Given we have may varieties of constructors, I think we have to stick to what’s best for us.
Neither of these methods of passing some sort of value, from what I understand, are able to pass a value that is a copy of the original value but that can’t affect the original value if the parametrized value is assigned something new.
Pardon?
If you don’t want the original objects to be changed, just declare the references const:
Foo(const int& val1, const int& val2):
Anyway that’s not a problem in your code, since you anyway copy them into the class prorperties:
num1{ val1 }, num2{ val2 }
The compiler can tell pointers and not pointers apart, if you really, really, really need that (I’m not suggesting it’s a good idea):
|
|
Output:
Arguments passed by copy Arguments passed by copy Arguments passed by pointers
@Enoizat- I didn’t think about «const». That qualifier would definitely accomplish what I want it to since it would eliminate ambiguity and serve to provide a non-alterable copy.
Topic archived. No new replies allowed.
Problem
Suppose you have a JsonDocument
, named doc
, and you want to print the value "myValue"
.
If you do this:
Serial.println(doc["myValue"]);
you’ll get the following compilation error:
call of overloaded 'println(ArduinoJson6101_00000::enable_if<true, ArduinoJson6101_00000::MemberProxy<ArduinoJson6101_00000::JsonDocument&, const char*> >::type)' is ambiguous
Quite scary, right?
Explanation
It’s not that complicated. The compiler tells us that we passed some obscure type to Serial.println()
and that he didn’t know which overload of println()
to choose.
What’s an overload, you ask? When the same function has several versions with different parameters, we call each version an “overload.” In our case, Serial.println()
has 12 overloads:
size_t println(const __FlashStringHelper *);
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
size_t println(const Printable&);
size_t println(void);
As you can see, there is no overload for JsonVariant
, so how can the compiler decide which one to use?
Solution
There are two ways to solve the ambiguity:
- You can explicitly cast the
JsonVariant
to type supported byprintln()
- You can avoid
println()
The first solution only works if you know the type of the value. For example, if you know that "myValue"
contains an integer, you can write:
Serial.println(doc["myValue"].as<int>());
However, if you don’t know the type, you must use the second solution: replace println()
with serializeJson()
:
serializeJson(doc["myValue"], Serial);
What about Printable
?
As you saw above, println()
has an overload that takes a Printable
, an interface that allows supporting custom types. If JsonVariant
implemented Printable
, the call to println()
would not be ambiguous. So why ArduinoJson doesn’t do that?
Unfortunately, implementing Printable
makes the code of the library significantly bigger, and having a small footprint is one of the primary goals of ArduinoJson. Early versions supported Printable
, but this feature was removed because it was not worth the extra bytes.
Causes[edit | edit source]
Arguments in a function call do not match those in any function declaration[edit | edit source]
For example, a function, «foo», is called from inside main with an argument that is not a perfect match for any of the currently existing implementations of «foo».
void foo(int x); void foo(double x); int main () { long x = 5000; foo(x); ...
Solution 1: Cast the argument to match a declaration
int main () { long x = 5000; foo((int)x);
Solution 2: Create a new, overloaded version of the called function to match the arguments
void foo(int x); void foo(double x); void foo(long x); int main () { long x = 5000; foo(x);
The same function is defined more than once[edit | edit source]
Solution 1: Look for a misspelled or duplicate function definition/declaration
Solution 2: Make sure you’re not using a function name defined in the standard library
template <typename T> void swap(T &a, T &b) { // error, "swap" is defined by the C++ standard library T tmp = a; a = b; b = tmp; } // Possible Fix template <typename T> void Swap(T &a, T &b) { // Capitalized the first letter T tmp = a; a = b; b = tmp; }
Notes[edit | edit source]
- Message found in GCC versions 3.2.3, 4.5.1
Я не знаком с шаблонами. Я только начал изучать это. Почему я получаю ошибки в следующей программе?
#include <iostream>
#include <string>
using std::cout;
using std::string;
template<class C>
C min(C a,C b) {
return a<b?a:b;
}
int main()
{
string a="first string";
string b="second string";
cout<<"minimum string is: "<<min(a,b)<<'n';
int c=3,d=5;
cout<<"minimum number is: "<<min(c,d)<<'n';
double e{3.3},f{6.6};
cout<<"minimum number is: "<<min(e,f)<<'n';
char g{'a'},h{'b'};
cout<<"minimum number is: "<<min(g,h)<<'n';
return 0;
}
Ошибки:
13 [Error] call of overloaded 'min(std::string&, std::string&)' is ambiguous
6 [Note] C min(C, C) [with C = std::basic_string<char>]
Пожалуйста, помогите мне.
11
Решение
Здесь происходит две вещи.
Ваша первая проблема заключается в том, что вы включили только часть сообщения об ошибке. Вот ссылка на код, выполняемый в gcc и clang, и одно из полученных сообщений об ошибке (полностью):
main.cpp:13:34: error: call to 'min' is ambiguous
cout<<"minimum string is: "<<min(a,b)<<'n';
^~~
/usr/include/c++/v1/algorithm:2579:1: note: candidate function [with _Tp = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
min(const _Tp& __a, const _Tp& __b)
^
main.cpp:6:3: note: candidate function [with C = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
C min(C a,C b) {
^
Есть два кандидата. Один в main.cpp:6:3
(строка 6, символ 3) и один на algorithm:2579:1
(строка 2579, символ 1).
Один из них ты написал, а один из них в #include <algorithm>
,
Один из ваших заголовочных файлов включен <algorithm>
без тебя об этом. Стандартные заголовки могут делать это, как бы это ни раздражало.
В <algorithm>
Eсть std::min
шаблон функции. Как std::string
это экземпляр класса шаблона в namespace std
, шаблон функции std::min
обнаруживается с помощью процесса, называемого «поиск с учетом аргументов» или «поиск по Кенигу». (Кандидаты перегрузки функции ищутся локально, а также в пространствах имен аргументов функции, а также в пространствах имен аргументов шаблона для аргументов функции и в пространствах имен вещей, на которые указывают аргументы объекта. функция и т. д.)
Ваша местная функция min
также находится в том же пространстве имен, что и тело main
,
Оба одинаково хороши, и компилятор не может решить, какой из них вы хотите вызвать. Так что выдает ошибку, сообщающую вам об этом.
И gcc и clang делают error:
затем последовательность note:
s. Обычно все из note:
s после ошибки важны для понимания ошибки.
Чтобы это исправить, попробуйте позвонить ::min
(полностью квалифицируя вызов), или переименовав функцию во что-то другое, или сделайте вашу версию более подходящей, чем std::min
(сложно, но выполнимо в некоторых случаях), или вызов (min)(a,b)
, Последний блокирует поиск ADL / Koenig, а также блокирует раскрытие макроса (например, если какая-то ОС вставила #define min
макросы в их системные заголовки) (через @ 0x499602D2).
14
Другие решения
Вы столкнулись с именным столкновением с std::min
, Скорее всего, он включен в один из других стандартных заголовков библиотеки, которые вы включили, либо <iostream>
или же <string>
моё предположение, вероятно, последнее. Быстрое решение состоит в том, чтобы переименовать вашу функцию. Например, переименовав его в mymin
работает отлично. демонстрация
5
[progeR] 30 / 8 / 2 Регистрация: 20.08.2011 Сообщений: 615 |
||||||||
1 |
||||||||
22.12.2016, 22:31. Показов 6307. Ответов 14 Метки нет (Все метки)
Добрый вечер.
При записи:
пишет: Код call of overloaded template function is ambiguous. В качестве кандидатов предлагает эти мои две метода. Удалить второй метод и записать первый с uint8_t count = sizeof(T) не очень хотелось бы.
__________________
0 |
2549 / 1208 / 358 Регистрация: 30.11.2013 Сообщений: 3,826 |
|
22.12.2016, 22:33 |
2 |
[progeR], разве «по умолчанию» может быть не в конце?
0 |
[progeR] 30 / 8 / 2 Регистрация: 20.08.2011 Сообщений: 615 |
||||
22.12.2016, 22:41 [ТС] |
3 |
|||
Так работает. Получается может.
0 |
2549 / 1208 / 358 Регистрация: 30.11.2013 Сообщений: 3,826 |
|
22.12.2016, 22:55 |
4 |
[progeR], я тихо спросил?
0 |
tapochka 42 / 42 / 17 Регистрация: 25.04.2014 Сообщений: 499 |
||||
23.12.2016, 04:02 |
5 |
|||
работает, правда не знаю как грамотно в forward эти auto&& засунуть при передаче во второй функции:
0 |
hoggy 8719 / 4299 / 958 Регистрация: 15.11.2014 Сообщений: 9,744 |
||||
23.12.2016, 12:00 |
6 |
|||
разве «по умолчанию» может быть не в конце? это не код, это шандец какой то. ну то есть первые два были указаны явно. косяк же приключился потому, фишка в том, что даже если бы каста не было,
я не могу сказать точно, почему так. кастую DrOffset в тред
1 |
TheCalligrapher Вездепух 10435 / 5704 / 1553 Регистрация: 18.10.2014 Сообщений: 14,098 |
||||
23.12.2016, 12:45 |
7 |
|||
Сообщение было отмечено hoggy как решение Решение
Я не понял, что ему не ясно? Второй параметр шаблона — число (а не булево значение). Значит все должно определяться однозначно. В С++ выбор лучшей функции-кандидата в процессе overload resolution выполняется только на основе того, как хорошо типы аргументов функции соответствуют типам параметров функции. Насколько же хорошо типы нетиповых (non-type) аргументов шаблона соответствуют типам нетиповых параметров шаблона значения не имеет и никогда не имело. И на overload resolution это никакого влияния не оказывает. В С++ нет механизма «предпочтения» тех или иных версий перегруженного шаблона на основе того, как «хорошо» совпадали типы шаблонных аргументов. Компилятор интересует лишь то, является ли аргумент допустимым для данного параметра. Все, что компилятор должен сделать — это нагенерировать из ваших шаблонов набор функций-кандидатов, к которым потом будет применяться overload resolution. Все что для этого надо — это чтобы шаблон функции успешно специализировался. Если нетиповой параметр шаблона является целочисленным значением, то любой целочисленный аргумент, который не требует сужающего преобразования (narrowing conversion) является допустимым аргументом шаблона. Так как преобразование Я бы даже сказал, что существует больше риска того, что ваш первый шаблон будет исключен из рассмотрения, ибо преобразование — Но это еще пол-дела. Даже если бы в С++ существовал некий механизм мета-overload resolution, рассматривающий на нетиповые параметрах шаблонов, у вас бы все равно сохранилась неоднозначность. Точного соответствия-то у вас нет. Для первого шаблона требуется преобразование
2 |
8719 / 4299 / 958 Регистрация: 15.11.2014 Сообщений: 9,744 |
|
23.12.2016, 12:55 |
8 |
Так как преобразование unsigned -> bool формально не является сужающим sizeof(bool) — 1.
0 |
Вездепух 10435 / 5704 / 1553 Регистрация: 18.10.2014 Сообщений: 14,098 |
|
23.12.2016, 13:14 |
9 |
Сообщение было отмечено hoggy как решение Решение
почему компиляется первый test Не понимаю, что тут может быть непонятного. Первый шаблон даже отдаленно не подходит, ибо типовой аргумент Поправка: Тут я не прав. Первый вызов не должен компилироваться из-за сужающей конверсиии (см. ниже).
(причем через жёпь), ??? (Недоумение) Добавлено через 12 минут
sizeof(bool) — 1. Тут ситуация интересная. Конверсия https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57891 В clang, пишут, исправили (не знаю, везде ли). Что же касается преобразования То есть в случае ТС действительно имеет место безобразие с некоторыми компиляторами, допускающими сужающую конверсию в тех контекстах, когда она запрещена.
2 |
8719 / 4299 / 958 Регистрация: 15.11.2014 Сообщений: 9,744 |
|
23.12.2016, 13:22 |
10 |
Первый шаблон даже отдаленно не подходит, ибо типовой аргумент int никак не может быть передан через нетиповой параметр bool wait. ничего не понял.
??? (Недоумение) говнокод — такой говнокод.
В чем затруднение? уже ни в чем.
Насколько же хорошо типы нетиповых (non-type) аргументов шаблона соответствуют типам нетиповых параметров шаблона значения не имеет и никогда не имело. это разъясняет ситуацию со вторым тестом. мерси. Добавлено через 6 минут
0 |
TheCalligrapher Вездепух 10435 / 5704 / 1553 Регистрация: 18.10.2014 Сообщений: 14,098 |
||||
23.12.2016, 13:24 |
11 |
|||
ничего не понял. Еще раз, посмотрите внимательнее на первый шаблон. У него параметры Вы же в ваших вызовах
явно передаете Это никак не может подойти к первому шаблону. Поэтому первый шаблон в ваших вызовах вообще отбрасывается сразу и более не рассматривается. Рассматривается только второй шаблон. У него параметры При этом первый вызов формально неверен из-за сужающего преобразования значения
1 |
8719 / 4299 / 958 Регистрация: 15.11.2014 Сообщений: 9,744 |
|
23.12.2016, 13:32 |
12 |
Вы же в ваших вызовах ааа! блин! точно))
0 |
TheCalligrapher Вездепух 10435 / 5704 / 1553 Регистрация: 18.10.2014 Сообщений: 14,098 |
||||||||
23.12.2016, 13:44 |
13 |
|||||||
Код ТС:
Clang, в котором этот баг исправлен, спокойно компилирует http://coliru.stacked-crooked…. 2c62493b19 А GCC до сих пор глючит http://coliru.stacked-crooked…. 41e25acd46 Добавлено через 5 минут
выдает предупреждение о сужающем преобразовании, то есть формально удовлетворяет требованию о необходимости диагностического сообщения. Но ситуацию с кодом ТС в Visual Studio 2015 это не спасает, ибо это «просто предупреждение».
3 |
notAll |
||||
23.12.2016, 15:59
#14 |
||||
Не по теме:
не знаю как грамотно в forward эти auto&& засунуть при передаче Думаю что так:
0 |
tapochka 42 / 42 / 17 Регистрация: 25.04.2014 Сообщений: 499 |
||||
23.12.2016, 22:22 |
15 |
|||
Не по теме: notAll, все-таки вроде так:
Добавлено через 7 минут Не по теме: хотя не, с константами проблема
0 |
Let’s say we want to write a templated function with a specialized version for integral types and a generic version for all other types. My naive attempt looked like this and resulted in a call of overloaded ‘func(int)’ is ambiguous
compiler error:
#include <iostream>
#include <type_traits>
template<typename T>
void func(const T& x) {
std::cout << "generic: " << x << std::endl;
}
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void func(const T& x) {
std::cout << "specialized: " << x << std::endl;
}
int main() {
func(5);
return 0;
}
Adding the negated template condition to the generic function declaration fixes it:
template<typename T, typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr>
...
But it’s somewhat redundant and becomes annoying if we want to add another overload, for example, for floating point types. Then the generic version becomes:
template<typename T,
typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr,
typename std::enable_if<!std::is_floating_point<T>::value>::type* = nullptr,
>
...
Is there a cleaner way to write the generic version without having to duplicate all specialized declarations?