c++ variadic template: can't match function - c++

Here is my code:
#include <iostream>
#include "Generator.h" // user-defined class
char getChar(Generator & generator)
{
return generator.generateChar();
}
char getChar(int pos, const string & s)
{
return s[pos];
}
template<typename... StringType>
void func(Generator & generator, StringType &&... str)
{
char ch;
int size = sizeof...(StringType);
// lots of things to do
if (size == 0)
{
ch = getChar(generator);
}
else
{
ch = getChar(1, std::forward<StringType>(str)...); // ERROR here
}
}
int main(int argc, char ** argv)
{
Generator generator;
func(generator);
func(generator, "abc");
return 0;
}
At the beginning I just overloaded the function func and I found there were many similar codes. So I'm considering using the variadic template to get a better design. (How to make a better design if two overload functions are similar)
However I don't know why there is an error:
main.cpp:27:8: error: no matching function for call to 'getChar'
ch = getChar(1, std::forward(str)...);
main.cpp:37:2: note: in instantiation of function template specialization 'func<>' requested here
func(generator);
main.cpp:6:6: note: candidate function not viable: no known conversion from 'int' to 'Generator &' for 1st argument char
getChar(Generator & generator)
main.cpp:11:6: note: candidate function not viable: requires 2 arguments, but 1 was provided char getChar(int pos, const string & s)
By the way, can I have some design to avoid using if...else... working with sizeof...(StringType)?

When a template gets expanded, the entire template code gets expanded, and compiled, in its entirety.
Let's see what happens here:
func(generator);
In the resulting template-generated function, size will be 0, and the resulting function becomes:
if (0 == 0)
{
ch = getChar(generator);
}
else
{
ch = getChar(1);
}
Your compilation error becomes very obvious: getchar(1); does not match any overloaded instance of getChar(). The fact that the if statement is going to always evaluate to true, and the else part will never be executed doesn't matter. The else part must still be valid C++ code, that gets compiled, and it gets optimized away (maybe) only after it is compiled. And it can't be compiled, hence the compilation error.
Now that answers your question "I don't know why there is an error". Now you know. How to fix this becomes a different question, with the answer being, depending on the exact situation, some combination of template specialization, and/or SFINAE.
It looks like the example in your question is an abbreviated example (since the template function will never work, obviously, if the parameter pack has two or more parameters). That's fine (and is 100% compliant with the spirit of showing a minimum, complete, verifiable example), but coming up with an alternative compilable version of the shown code would probably not answer your real question.

Related

What is the proper definition for a constexpr function that take a character array?

I'm writing a hashing function to help speed up string comparisons.
My codebase compares strings against a lot of const char[] constants, and it would be ideal if I could work with hashes instead. I went ahead and translated xxHash to modern C++, and I have a working prototype that does work at compile time, but I'm not sure what the function definition should be for the main hashing function.
At the moment, I have this:
template <size_t arr_size>
constexpr uint64_t xxHash64(const char(data)[arr_size])
{...}
This does work, and I am able to do a compile time call like this
constexpr char myString[] = "foobar";
constexpr uint64_t hashedString = xxHash64<sizeof myString>(myString);
[Find a minimal example here]
All good so far, but I would like to add a user-defined literal wrapper function for some eye candy, and this is where the problem lies.
UDLs come with a fixed prototype, as specified here
The Microsoft doc stipulates "Also, any of these operators can be defined as constexpr".
But when I try to call my hashing function from a constexpr UDL:
constexpr uint64_t operator "" _hashed(const char *arr, size_t size) {
return xxHash64<size>(arr);
}
function "xxHash64" cannot be called with the given argument list
argument types are: (const char*)
And the error does make sense. My function expects a character array, and instead it gets a pointer.
But if I were to modify the definition of my xxHash64 function to take a const char *, I can no longer work in a constexpr context because the compiler needs to resolve the pointer first, which happens at runtime.
So am I doing anything wrong here, or is this a limitation of UDLs or constexpr functions as a whole?
Again, I'm not 100% sure the templated definition at the top is the way to go, but I'm not sure how else I could read characters from a string at compile time.
I'm not limited by any compiler version or library. If there is a better way to do this, feel free to suggest.
there is no problem to call constexpr function with constexpr pointer as constant expression
constexpr uint64_t xxHash64(const char* s){return s[0];}
constexpr uint64_t operator "" _g(const char *arr,std::size_t){
return xxHash64(arr);
}
int main()
{
xxHash64("foo");
constexpr auto c = "foobar"_g;
return c;
}
would just work fine.
with c++20, you can also get the size as constant expression with string literal operator template.
#include <cstdint>
template <std::size_t arr_size>
constexpr std::uint64_t xxHash64(const char(&data)[arr_size]){
return data[0];
}
// template <std::size_t N> // can also be full class template (with CTAD)
struct hash_value{
std::uint64_t value;
template <std::size_t N>
constexpr hash_value(const char(&p)[N]):value(xxHash64(p)){}
};
template < hash_value v >
constexpr std::uint64_t operator ""_hashed() { return v.value; }
int main()
{
constexpr auto v = "foobar"_hashed;
return v;
}

Expansion of types from comparison

I know the following code does not work, and I fully understand why. What I actually do not understand is why not:
int main(int argc, char *argv[]) {
std::cout << (atoi(argv[1]) ? "foo" : 'b') << std::end;
}
Why: Of course, this expression may generate either a string or an integer, and this is the error pointed by the compiler:
error: operands to ?: have different types ‘const char*’ and ‘char’
Why not: Since the operator<< have a bind with both of the types const char* and char, why is it the compiler don't perform a code expansion as in a template -- which, I guess, is what is performed.
For example, if I had:
template <class T>
void a(const T& value) {
std::cout << a << std::endl;
}
I could call either a("foo") and a('b'), and -- I guess -- the compiler would do one expansion of the function with the type name [T = const char*] and another one with [T = char].
This may be a simple matter of what C++ does -- and what it does not --, but I fail to see if there's any corner case that would come up as an error if the expansion was performed.
C++ is a compiled statically-typed language and the type of an expression must be known at compile-time. The expression atoi(argv[1]) ? "foo" : 'b' could be a const char* or char, depending on the value of argv[1], which can't be known at compile-time. It's only when the program is actually executed that this value is known. So when the compiler is attempting to turn this expression into machine code, it can't decide which type to treat the expression as.
To see that it really doesn't have anything to do with the operator<<, just have the expression by itself:
int main(int argc, const char* argv[])
{
atoi(argv[1]) ? "foo" : 'b';
}
Even this won't compile, giving the following error:
error: operands to ?: have different types ‘const char*’ and ‘char’
It has nothing to do with cout or operator <<. The expression
atoi(argv[1]) ? "foo" : 'b'
itself wouldn't compile. The 2nd and 3rd operators that you feed to ?: must be either the same type, or types that are implicitly convertible to one other.
This is what you think you should be asking for:
#include <iostream>
#include <utility>
#include <type_traits>
#include <functional>
template<typename Left, typename Right>
auto tri( bool b, Left&& left, Right&& right )
-> decltype( std::forward<Left>(left)() )
{
if (b)
return std::forward<Left>(left)();
else
return std::forward<Right>(right)();
}
int main(int /*argc*/, char *argv[]) {
tri(
atoi(argv[1]),
[]()->std::ostream&{ return std::cout<<"foo"; },
[]()->std::ostream&{ return std::cout<<'b'; }
) << std::endl;
}
but it isn't what ? does.
C++ could be modified to do what you are asking, but the type cascade would grow boundlessly. Each time you have an expression that could return type A or type B, the calling code would have to be forked, which could cause further forking.
Signatures of functions would have to be expanded to list all of the types it "could" return.
Now, while this may be a worthwhile feature for C++ in the future, it isn't what C++ does now. Each expression in C++ has a single, definite type -- in template code, this occurs when you have instantiated the template.
As an aside, the ability to have poly-type return values in C++ would give you capabilities similar to exception handling, where a function could return a value or an error flag. As the calling code would have to automatically fork whenever you call a poly-type return value function, it would have to handle that error flag (either by returning it as an alternative type, or by handling it locally).

Ways to distinguish string literal and runtime generated string

Suppose I have a function that takes a string as input:
SomeOutputType f_impl(const char* s);
Most call sites just use string literals as input, e.g. f("Hello, world"). Suppose I have implemented the following function to compute the result at compile time
template <char...> SomeOutputType f_impl();
My question is, is there a way to let the call sites like f("Hello, world") calls the templated form, while for general call sites like string s="Hello, world"; f(s.c_str()); calls the general form? For clarification, auto s = "Hello, world"; f(s); don't have to call the templated form because s is now a variable and no longer a compile time constant.
A useful case for this question is to optimize printf. In most cases the format will be string literals so a lot of things can be done at compile time to optimize things, instead of parsing the format at runtime.
No, a string literal like "foo" has the type const char[S + 1] where S is the number of characters you wrote. It behaves like an array of that type with no special rules.
In C++03, there was a special rule that said that a string literal could convert to char*. That allowed you to say
#define isStringLiteral(X) \
isConvertibleToCharStar(X) && hasTypeConstCharArray(X)
For example isStringLiteral(+"foo") would yield false, and isStringLiteral("foo") would yield true. Even this possibiliy would not have allowed you to call a function with a string literal argument and behave differently.
C++11 removed that special conversion rule and string literals behave like any other arrays. In C++11 as a dirty hack you can compose some macros, matching some simple string literals without handling escape sequences
constexpr bool isStringLiteral(const char *x, int n = 0) {
return *x == '"' ?
n == 0 ?
isStringLiteral(x + 1, n + 1)
: !*(x + 1)
: (*x && n != 0 && isStringLiteral(x + 1, n + 1));
}
#define FastFun(X) \
(isStringLiteral(#X) ? fConstExpr(X, sizeof(X) - 1) : f(X))
While I haven't tested this, I think if you just declare the function constexpr and compile with high optimization, the compiler will compute at compile time whenever possible. As a bonus, you don't need to write the code twice. On the other hand, you have to write it once in constexpr style.
If I understand the question correctly, I actually think something like this is possible using a function overload. Here's an article that shows the basic idea. In your case I think it would be sufficient to have the following two overloads:
void f(char const *);
template<unsigned int N>
void f(char const (&)[N]);
The latter should be invoked when the string is a string literal, the latter at other times. If the compiler is sufficiently good at optimizing then calls to the latter may be evaluated at compile time.
EDIT:
Alright, it bothered me that the above solution didn't work, so I did some playing around and I think I came up with a solution:
#include <string>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct is_string_literal {
enum { value = false };
};
template<unsigned int N>
struct is_string_literal<char const (&)[N]> {
enum { value = true };
};
template<typename T>
typename boost::disable_if<is_string_literal<T> >::type
foo(T) {
std::cout << "foo1" << std::endl;
}
template<int N>
void foo(char const (&)[N]) {
std::cout << "foo2" << std::endl;
}
int main( ) {
std::string bar = "blah";
char const str[] = "blah";
foo(str);
foo("blah");
foo(bar.data());
}
The output (on GCC 4.4 with -O3) is:
foo2
foo2
foo1
I admit that I don't completely understand why this works when the previous solution didn't. Maybe there's something about overload resolution that I don't completely understand.

Template won’t infer size of zero-length array in C++

Let’s say I have a template function that infers the length of an array parameter.
template <size_t S>
void join(const char d[], const char *(&arr)[S]) { }
If I call it like this, all is well:
const char *messages[] = {
"OK",
"Not OK",
"File not found"
};
join("\n", messages);
But if I call it with an empty array, like this:
const char *messages[] = { };
join("\n", messages);
…it doesn’t compile (with clang 4.0):
targs.cpp:9:5: error: no matching function for call to 'join'
join("\n", messages);
^~~~
targs.cpp:4:6: note: candidate template ignored: substitution failure [with S = 0]
void join(const char d[], const char *(&arr)[S]) { }
^
1 error generated.
I’m guessing that it has something to do with C++ not liking zero-length arrays, but if the function is not a template and takes the length as a separate parameter, it doesn’t complain about me declaring messages as a zero-length array.
What’s up here, and is there a nice workaround?
My actual use case is defining the parameters an HTTP API endpoint takes and looks something like this:
const api_param_t params[] = {
{ API_TYPE_STRING, "foo" },
{ API_TYPE_UINT64, "bar" },
{ API_TYPE_STRING, "baz" }
}
const api_status_t status_codes[] = { … };
const api_middleware_t middleware[] = { … };
new api_endpoint("/foo", params, status_codes, middleware);
Most endpoints take at least one parameter but many take none. It looks like this is, indeed, an extension which both GCC and clang implement (but, looks like, not completely…). I can think of a few workarounds:
Overload the api_endpoint constructor to special case zero-length arguments (but I need 23 of them to cover each zero-length-able parameter), which the GCC/clang extension is OK with.
Don’t try to infer the array length, take it as a separate parameter (and continue to use zero-length arrays)
Use a higher-level data structure like a vector for these parameters
Use a magic value to indicate "empty"
…but if anyone has better ideas I’d love to hear ‘em
This code isn't legal in the first place:
const char *messages[] = { };
Here are the errors and warnings my compiler produces:
main.cpp:6:26: warning: zero size arrays are an extension [-Wzero-length-array]
const char *messages[] = { };
^
main.cpp:7:1: error: no matching function for call to 'join'
join("\n", messages);
^~~~
main:3:6: note: candidate template ignored: substitution failure [with S = 0]: zero-length arrays are not permitted in C++
void join(const char d[], const char *(&arr)[S]) { }
^ ~
1 warning and 1 error generated.
So zero length arrays aren't actually allowed at all. Your compiler appears to have an extension for zero length arrays which, however, does not cover this specific case. Extensions are like that sometimes, because less work goes into extensions to make them work consistently with the whole language.
A workaround will depend on why you want a zero length array and how you're using it elsewhere. One workaround might be using a single element array instead.
Here's a work around. Since the extension does not allow array sizes to be deduced as zero add an overload that does not require this deduction:
template <size_t S>
void join(const char d[], const char *(&arr)[S]) {
std::cout << "array length > 0\n";
}
void join(const char d[], const char *(&arr)[0]) {
std::cout << "extension, zero length array\n";
}
int main() {
const char *messages[] = {
"OK",
"Not OK",
"File not found"
};
join("\n", messages);
const char *messages2[] = { };
join("\n", messages2);
}
You should keep in mind that this is using an extension and is not portable code. You may prefer to write portable code in order to avoid being locked into any particular C++ implementation. You can see how much you rely on this extension by adding the flag -Wzero-length-array to your builds.

Template compilation error in Sun Studio 12

We are migrating to Sun Studio 12.1 and with the new compiler [ CC: Sun C++ 5.10 SunOS_sparc 2009/06/03 ]. I am getting compilation error while compiling a code that compiled fine with earlier version of Sun Compiler [ CC: Sun WorkShop 6 update 2 C++ 5.3 2001/05/15 ].
This is the compilation error I get.
"Sample.cc": Error: Could not find a match for LoopThrough(int[2])
needed in main(). 1 Error(s) detected.
*** Error code 1.
CODE:
#include <iostream>
#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";
template<size_t SZ>
void LoopThrough(const int(&Item)[SZ])
{
PRINT_TRACE("Specialized version");
for (size_t index = 0; index < SZ; ++index)
{
std::cout << Item[index] << "\n";
}
}
/*
template<typename Type, size_t SZ>
void LoopThrough(const Type(&Item)[SZ])
{
PRINT_TRACE("Generic version");
}
*/
int main()
{
{
int arr[] = { 1, 2 };
LoopThrough(arr);
}
}
If I uncomment the code with Generic version, the code compiles fine and the generic version is called. I don't see this problem with MSVC 2010 with extensions disabled and the same case with ideone here.
The specialized version of the function is called. Now the question is, is this a bug in Sun Compiler ?
If yes, how could we file a bug report ?
The compiler is not following the standard in this case and is buggy. Let's review the relevant sections.
First from 13.3/3 we have:
...
— First, a subset of the candidate functions—those that have the
proper number of arguments and meet certain other conditions—is
selected to form a set of viable functions (13.3.2).
— Then the best viable function is selected based on the implicit
conversion sequences (13.3.3.1) needed to match each argument to the
corresponding parameter of each viable function.
So both functions have the same number of arguments and are considered candidates. Now we have to find the best viable function, in
13.3.3:
let ICSi(F) denote the implicit conversion sequence that converts the
ith argument in the list to the type of the ith parameter of viable
function F. 13.3.3.1 defines the implicit conversion sequences and
13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than
another
Then we have
Given these definitions, a viable function F1 is defined to be a
better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than
ICSj(F2), or, if not that,
— F1 is a nontemplate function and F2 is a
template function specialization, or, if not that,
— F1 and F2 are
template functions, and the function template for F1 is more
specialized than the template for F2 according to the partial ordering
rules described in 14.5.5.2, or, if not that,
The two functions are equal for the first rule (adding const), and the second rule doesn't apply (both are templates). So we move to the third rule. From 14.5.5.2 (which I will quote if requested) we learn that the const int version of the function is more specialized than the const Item version, and so the best match is the const int overload, which should then be called.
Your best temporary fix is probably a second overload:
template<size_t SZ>
void LoopThrough(int (&Item)[SZ])
{
LoopThrough(static_cast<const int (&)[SZ]>(Item));
}
Your compiler is buggy. Both overloads have their template arguments deduced, and overload resolution should select the most specialized one. So apart from getting a new compiler, what can you do?
First, it's helpful to realize that -even with conforming compilers- it is generally not a good a idea to have different function template overloads. See e.g. Item 66 of C++ Coding Standards: 101 Rules, Guidelines, and Best Practices by Herb Sutter and Andrei Alexandrescu.
Fortunately, that Item also suggests a possible fix. All you have to do is define a single function template and let that function template delegate the work to a class template function object. You can then partially specialize this class template for ints.
#include <iostream>
#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";
namespace detail {
// primary template
template<typename Type, size_t SZ>
class LoopThroughHelper
{
public:
void operator()(const Type(&Item)[SZ])
{
PRINT_TRACE("Generic version");
}
};
// partial specialization for int arrays
template<size_t SZ>
class LoopThroughHelper<int, SZ>
{
public:
void operator()(const int(&Item)[SZ])
{
PRINT_TRACE("Specialized version");
for (size_t index = 0; index < SZ; ++index)
{
std::cout << Item[index] << "\n";
}
}
};
} // namespace detail
// one function template to rule them all
template<typename Type, size_t SZ>
void LoopThrough(const Type(&Item)[SZ])
{
detail::LoopThroughHelper<Type, SZ>()(Item);
}
int main()
{
{
int arr[] = { 1, 2 };
LoopThrough(arr);
}
}
Most likely, the compiler will inline the call to the function object and completely optimize away the temporary. Hopefully your compiler will also have correctly implemented partial specialization of class templates.
Output on Ideone