Related
I have two broadly related questions.
I want to make a function that forwards the arguments to fmt::format (and later to std::format, when the support increases). Something like this:
#include <iostream>
#include <fmt/core.h>
constexpr auto my_print(auto&& fmt, auto&&... args) {
// Error here!
// ~~~~~~~~v~~~~~~~~
return fmt::format(fmt, args...);
}
int main() {
std::cout << my_print("{}", 42) << std::endl;
}
Tested with gcc 11.1.0:
In instantiation of ‘constexpr auto my_print(auto:11&&, auto:12&& ...) [with auto:11 = const char (&)[3]; auto:12 = {int}]’:
error: ‘fmt’ is not a constant expression
And tested with clang 12.0.1:
error: call to consteval function 'fmt::basic_format_string<char, int &>::basic_format_string<char [3], 0>' is not a constant expression
In the library (core.h) it's declared something like this:
template <typename... T>
auto format(format_string<T...> fmt, T&&... args) -> std::string {
// ...
}
The problem is that cppreference indicates that the type of the first parameter is unspecified. So
How can I make a function like my_print that passes the arguments to fmt::format and still catches the same kind of errors? Is there a more general way to do this for any kind of function?
How can I infer the type of a parameter of a function like std::format?
For more context, I want to make a function that calls to std::format conditionally, avoiding the formatting at all if the string won't be needed. If you know a better way to make this leave a comment, I'll be very greatful. However, my question about how to solve the general problem still stands.
C++23 may include https://wg21.link/P2508R1, which will expose the format-string type used by std::format. This corresponds to the fmt::format_string type provided in libfmt. Example use might be:
template <typename... Args>
auto my_print(std::format_string<Args...> fmt, Args&&... args) {
return std::format(fmt, std::forward<Args>(args)...);
}
Before C++23, you can use std::vformat / fmt::vformat instead.
template <typename... Args>
auto my_print(std::string_view fmt, Args&&... args) {
return std::vformat(fmt, std::make_format_args(std::forward<Args>(args)...));
}
https://godbolt.org/z/5YnY11vE4
The issue is that std::format (and the latest version of fmt::format) require a constant expression for the first parameter, as you have noticed. This is so that it can provide compile-time errors if the format string does not make sense for the passed-in arguments. Using vformat is the way to get around this.
Obviously this sidesteps the compile-time checking normally done for a format string: any errors with the format string will manifest as runtime errors (exceptions) instead.
I'm not sure if there's any easy way to circumvent this, apart from providing the format string as a template parameter. One attempt may be something like this:
template <std::size_t N>
struct static_string {
char str[N] {};
constexpr static_string(const char (&s)[N]) {
std::ranges::copy(s, str);
}
};
template <static_string fmt, typename... Args>
auto my_print(Args&&... args) {
return std::format(fmt.str, std::forward<Args>(args)...);
}
// used like
my_print<"string: {}">(42);
https://godbolt.org/z/5GW16Eac1
If you really want to pass the parameter using "normal-ish" syntax, you could use a user-defined literal to construct a type that stores the string at compile time:
template <std::size_t N>
struct static_string {
char str[N] {};
constexpr static_string(const char (&s)[N]) {
std::ranges::copy(s, str);
}
};
template <static_string s>
struct format_string {
static constexpr const char* string = s.str;
};
template <static_string s>
constexpr auto operator""_fmt() {
return format_string<s>{};
}
template <typename F, typename... Args>
auto my_print(F, Args&&... args) {
return std::format(F::string, std::forward<Args>(args)...);
}
// used like
my_print("string: {}"_fmt, 42);
https://godbolt.org/z/dx1TGdcM9
It's the call to the constructor of fmt::format_string that needs to be a constant expression, so your function should take the format string as a fmt::format_string instead of a generic type:
template <typename... Args>
std::string my_print(fmt::format_string<Args...> s, Args&&... args)
{
return fmt::format(s, std::forward<Args>(args)...);
}
I'm writting a simple C++ HTTP server framework. In my Server class, I can add Route's. Every route consists of a path, an HTTP method and a Controller (which is a pipeline of functions to be called when the request was made.) That Controller class is constructed by receiving a list of std::function's (or, more precisely: std::function<void(const HTTPRequest&, HTTPResponse&, Context&)>), but most of the time (or I should say every time), this Controller will be initialized with a list of lambda function literals, as in the following code:
server.add_route("/", HTTPMethod::GET,
{
[](auto, auto& response, auto&) {
const int ok = 200;
response.set_status(ok);
response << "[{ \"test1\": \"1\" },";
response["Content-Type"] = "text/json; charset=utf-8";
},
[](auto, auto& response, auto&) {
response << "{ \"test2\": \"2\" }]";
},
}
);
Being this the case, I would like to make the add_route function a constexpr, because, correct me if I am wrong, constexpr functions can be executed at compile time.
So, when I was making everything constexpr, I found the following error:
Controller.cpp:9:1 constexpr constructor's 1st parameter type 'Callable' (aka 'function<void (const HTTPRequest &, HTTPResponse &, Context &)>') is not a literal type
What I want to know is: why std::function's can't be literal types? Is there any way to circumvent this limitation?
Below is the code for Controller class. I'm aware that there are still other compile errors, but this is the main issue I'm tackling right now. Thanks in advance!
controller.hpp
#pragma once
#include <functional>
#include <initializer_list>
#include <vector>
#include "context.hpp"
#include "httprequest.hpp"
#include "httpresponse.hpp"
typedef std::function<void(const HTTPRequest&, HTTPResponse&, Context&)> Callable;
template <size_t N>
class Controller {
private:
std::array<Callable, N> callables;
public:
static auto empty_controller() -> Controller<1>;
constexpr explicit Controller(Callable);
constexpr Controller();
constexpr Controller(std::initializer_list<Callable>);
void call(const HTTPRequest&, HTTPResponse&, Context&);
};
controller.cpp
#include "controller.hpp"
template <size_t N>
auto Controller<N>::empty_controller() -> Controller<1> {
return Controller<1>([](auto, auto, auto) {});
}
template <>
constexpr Controller<1>::Controller(Callable _callable) :
callables(std::array<Callable, 1> { std::move(_callable) }) { }
template <>
constexpr Controller<1>::Controller() :
Controller(empty_controller()) { }
template <size_t N>
constexpr Controller<N>::Controller(std::initializer_list<Callable> _list_callables) :
callables(_list_callables) { }
template <size_t N>
void Controller<N>::call(const HTTPRequest& req, HTTPResponse& res, Context& ctx) {
for (auto& callable : callables) {
callable(req, res, ctx);
}
}
why std::function's can't be literal types? Is there any way to circumvent this limitation?
Because it uses type erasure in order to accept any callable. This requires polymorphism which cannot be constexpr until C++20 which will allow constexpr virtual.
You could use templates and capture the callable directly, but its type will creep into Controller and spread further.
Being this the case, I would like to make the add_route function a constexpr, because, correct me if I am wrong, constexpr functions can be executed at compile time.
Yes, if given constexpr arguments, the function will be executed at compile-time. Look at it like advanced constant folding. Furthermore constexpr methods used in compile-time context either cannot access *this or it has too be constexpr. In particular, constexpr method can only change the state of constexpr instance at compile time. Otherwise the function is run ordinarly at runtime.
The last point is relevant to you, running a HTTP server at compile-time hardly makes sense, so constexpr is probably not needed and it won't help anything.
EDIT constexpr behaviour example
struct Foo{
//If all members are trivial enough and initialized, the constructor is constexpr by default.
int state=10;
//constexpr Foo()=default;
constexpr int bar(bool use_state){
if(use_state)
return state++;
else
return 0;// Literal
}
constexpr int get_state()const{
return state;
}
};
template<int arg>
void baz(){}
int main(int argc, char* argv[])
{
Foo foo;
//Carefull, this also implies const and ::bar() is non-const.
constexpr Foo c_foo;
foo.bar(true);//Run-time, `this` is not constexpr even though `true` is
foo.bar(false);//Compile-time, `this` was not needed, `false` is constexpr
bool* b = new bool{false};
foo.bar(*b);//Always run-time since `*b` is not constexpr
//Force compile-time evaluation in compile-time context
//Foo has constexpr constructor, creates non-const (temporary) constexpr instance
baz<Foo().bar(true)>();
baz<Foo().bar(false)>();
baz<foo.bar(false)>();
//ERROR, foo is not constexpr
//baz<foo.bar(true)>();
//ERROR, c_foo is const
//baz<c_foo.bar(false)>();
//Okay, c_foo is constexpr
baz<c_foo.get_state()>();
//ERROR, foo is not constexpr
//baz<foo.get_state()>();
return 0;
}
I'm trying to make an object with a member function that calls another member function like so
foo foo1 = new foo(1, 2);
foo1.print(printj);
I have class:
class foo
{
public:
foo(int x, int y) {i = x; j = y;};
void const print(void const f());
void const printi();
void const printj();
private:
int i;
int j;
}
and my implementation is something like:
void const foo::printi(){
std::cout << i;
}
void const foo::printj(){
std::cout << j;
}
void const foo::print(void const f()){
f();
}
I'm getting an error of
[Error] no matching function for call to 'foo::print()'
Why is that, and how can i fix it?
You need to:
Declare the pointer-to-member function parameter as such:
void const print(void const (foo::*f)());
Pass the member function pointer correctly:
foo1.print(&foo::printj);
Call it with an actual instance (member function call requires an instance):
void const foo::print(void const (foo::*f)()){
(this->*f)();
}
Alternatively you can make the instance an additional parameter or use std::bind or boost::bind to bind them together.
that is not the way how to declare a pointer to a member function you have to declare it this way:
const void (Foo::*ptrFUnc)(void) // or any number of parameters and type
this example shows how:
#include <iostream>
using namespace std;
class Foo
{
public:
void print(const void(Foo::*Bar)()const)const;
const void FooBar()const;
const void Baz ()const;
};
void Foo::print(const void(Foo::*Bar)()const)const
{
(this->*Bar)();
}
const void Foo::FooBar()const
{
cout << "FooBar()" << endl;
}
const void Foo::Baz()const
{
cout << "Baz()" << endl;
}
int main()
{
Foo theFoo;
theFoo.print(theFoo.Baz);
theFoo.print(theFoo.FooBar);
return 0;
}
Note: This answer is aimed at general-case scenarios and future-proofing, and thus examines the possibility of accepting member functions with different numbers of arguments, and of modifying the function in the future. If this isn't an issue, the easiest solution is to manually specify the pointer-to-member-function, as described in the other answers.
A short summary is at the bottom.
There are also two alternatives to declaring the function's type manually, as shown in the other answers, both involving templates:
Declare it manually.
First alternative: Use templates to specialise the pointer-to-member-function, while explicitly specifying the class.
Second alternative: Use templates to deduce the pointer-to-member-function, with no explicit specifications.
In all three cases (manual declaration, and the two alternatives listed here), the usage syntax is identical:
foo1.print(&foo::printj);
As the other answers show, the syntax for declaring it manually is as follows:
// #1: Explicit declaration.
void const foo::print(void const (foo::* f)()) {
(this->*f)();
}
I won't go into much detail on this, as they already cover it. However, this option does have the issue that if you want to accept pointers to member functions which take one or more parameters, you need to manually overload it to accomodate this.
void const foo::print(void const (foo::* f)());
void const foo::print(void const (foo::* f)(int), int);
// And so on...
The first alternative looks a bit complex if you're not used to templates, but is relatively simple to implement.
// 2a: Simplest implementation.
template<typename Return, typename... ArgTypes>
void const foo::print(Return (foo::* f)(ArgTypes...), ArgTypes... args) {
(this->*f)(args...);
}
Or...
// 2b: Works roughly the same way, but gives cleaner, more readable error messages.
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print(Return (foo::* f)(ArgTypes...), Args... args) {
(this->*f)(args...);
}
This accepts any pointer-to-member-function which points to a member of foo, regardless of return and parameter types. If the function takes parameters, it also accepts a number of parameters equal to that function's.
Note that the primary difference between the two is that if not passed the correct number of parameters for the function, the first will give an error about not being able to deduce ArgTypes... due to mismatched template parameter packs, while the second will give an error about not having the correct number of parameters to call f().
[Mechanically, the difference is that the first uses the same template parameter pack in both the pointer and the parameter list, which requires that it be identical in both places (and thus detects the error as a deduction failure when print() is called), while the second uses a separate template parameter pack for each (and thus detects the error as a parameter count mismatch when the pointed-to function, f, is called).]
The second alternative looks cleaner still, and provides cleaner error messages.
template<typename MemberFunction>
void const foo::print(MemberFunction f){
(this->*f)();
}
This can be easily modified to accept member functions which take parameters, similarly to the first alternative.
// 3: Take pointer-to-member-function and any function parameters as template parameters.
template<typename MemberFunction, typename... Args>
void const foo::print(MemberFunction f, Args... args){
(this->*f)(args...);
}
It will also give the cleanest error message if passed the wrong number of parameters for the function, because the error occurs when calling f instead of at overload resolution or template deduction. This makes it the easiest to troubleshoot, if necessary.
So, this leaves us with three options, one of which can be done either of two ways:
class foo
{
public:
foo(int x, int y) {i = x; j = y; test = 42;};
// -----
// #1.
void const print1(void const (foo::* f)());
// -----
// #2.
template<typename Return, typename... ArgTypes>
void const print2a(Return (foo::* f)(ArgTypes...), ArgTypes... args);
template<typename Return, typename... ArgTypes, typename... Args>
void const print2b(Return (foo::* f)(ArgTypes...), Args... args);
// -----
// #3.
template<typename MemberFunction, typename... Args>
void const print3(MemberFunction f, Args... args);
// -----
void const printi();
void const printj();
// For testing.
void const printParams(int i, bool b, char c, double d);
private:
int i;
int j;
public:
int test;
};
void const foo::print1(void const (foo::* f)()) {
(this->*f)();
}
template<typename Return, typename... ArgTypes>
void const foo::print2a(Return (foo::* f)(ArgTypes...), ArgTypes... args) {
(this->*f)(args...);
}
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print2b(Return (foo::* f)(ArgTypes...), Args... args) {
(this->*f)(args...);
}
template<typename MemberFunction, typename... Args>
void const foo::print3(MemberFunction f, Args... args) {
(this->*f)(args...);
}
// -----
void const foo::printi(){
std::cout << i;
}
void const foo::printj(){
std::cout << j;
}
void const foo::printParams(int i, bool b, char c, double d) {
std::cout << std::boolalpha;
std::cout << i << ' ' << b << ' ' << c << ' ' << d << '\n';
std::cout << std::noboolalpha;
}
// -----
foo foo1(1, 2);
Now, mechanically, all three options will accept a pointer-to-member-function, and work as intended. There are a few key differences, however:
The first requires the most work to update and maintain (you have to explicitly overload it), but guarantees that print1() will only take pointers-to-member-functions that you specifically allow; if you want it to only take a void const (foo::*)(), it won't take a void const (foo::*)(int) instead. If passed incorrect arguments, its error messages will be the least useful.
The second only takes a pointer-to-member-function for the specified class, but accepts any pointer-to-member-function for that class; this makes it easier to update and maintain. If passed incorrect arguments, its error messages will be somewhat useful, but will usually be about template deduction. Of the two versions, print2b() will give cleaner error messages when passed the wrong number of parameters.
The third takes anything, but gives the cleanest, most useful error messages if used incorrectly. This is because the error is generated when you call f, instead of when you call print3(). This is as easy to update and maintain as the second option, and opens the possibility to perform dispatching based on the type of pointer it's passed.
So, to demonstrate the difference in error messages, let's see what happens if...
[Error messages paraphrased from Clang, GCC, and MSVC.]
[Note that MSVC template parameter lists have trouble with variadic templates, and can't properly output parameter packs. However, the function's name still contains the full template parameter list.]
If passed a pointer-to-member-function with no parameters: All four work properly.
foo1.print1(&foo::printj); // Output: 2
foo1.print2a(&foo::printj); // Output: 2
foo1.print2b(&foo::printj); // Output: 2
foo1.print3(&foo::printj); // Output: 2
If passed a pointer-to-member-function that takes parameters, and its parameters: print1() fails.
foo1.print1(&foo::printParams, 3, true, '&', 8.8); // Error: Too many arguments.
foo1.print2a(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
foo1.print2b(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
foo1.print3(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
If passed a pointer-to-member-function that takes parameters, and the wrong number of parameters: All four fail.
foo1.print1(&foo::printParams, 42); // Error: Too many arguments.
foo1.print2a(&foo::printParams, 42); // Error: Can't deduce template parameters,
// ArgTypes... could be <int, bool, char, double> or <int>.
foo1.print2b(&foo::printParams, 42); // Error: Not enough arguments to call f().
// Note: Clang deduces template parameters as:
// <const void, int, bool, char, double, int>
// Note: GCC deduces template parameters as:
// [with Return = const void; ArgTypes = {int, bool, char, double}; Args = {int}]
// Note: MSVC deduces template parameters as:
// <const void,int,bool,char,double,int>
foo1.print3(&foo::printParams, 42); // Error: Not enough arguments to call f().
// Note: Clang deduces template parameters as:
// <const void (foo::*)(int, bool, char, double), int>
// Note: GCC deduces template parameters as:
// [with MemberFunction = const void (foo::*)(int, bool, char, double); Args = {int}]
// Note: MSVC deduces template parameters as:
// <const void(__thiscall foo::* )(int,bool,char,double),int>
If passed a regular function pointer: All four fail.
void const bar() {}
foo1.print1(&bar); // Error: Can't convert void const (*)() to void const (foo::*)().
foo1.print2a(&bar); // Error: Can't deduce template parameters, mismatched function pointers.
foo1.print2b(&bar); // Error: Can't deduce template parameters, mismatched function pointers.
foo1.print3(&bar); // Error: void const (*)() isn't a pointer-to-member, can't be used with "->*".
If passed a pointer-to-member-function for the wrong class: All four fail.
class oof {
public:
void const printj() {}
};
foo1.print1(&oof::printj); // Error: Can't convert void const (oof::*)() to void const (foo::*)().
foo1.print2a(&oof::printj); // Error: Can't deduce template parameters, mismatched foo* and oof*.
foo1.print2b(&oof::printj); // Error: Can't deduce template parameters, mismatched foo* and oof*.
foo1.print3(&oof::printj); // Error: Can't use a void const (oof::*)() with a foo*.
If passed a pointer-to-member-data: All four fail.
foo1.print1(&foo::test); // Error: Can't convert int foo::* to void const (foo::*)().
foo1.print2a(&foo::test); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print2b(&foo::test); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print3(&foo::test); // Error: int foo::* can't be used as a function.
If passed a regular pointer: All four fail.
foo1.print1(&foo); // Error: Can't convert foo* to void const (foo::*)().
foo1.print2a(&foo); // Error: Can't deduce template parameters, mismatched
// foo* and Return (foo::*)(ArgTypes...).
foo1.print2b(&foo); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print3(&foo); // Error: foo* isn't a pointer-to-member, can't be used with "->*".
If passed an integral value: All four fail.
foo1.print1(3); // Error: Can't convert int to void const (foo::*)().
foo1.print2a(3); // Error: Can't deduce template parameters, mismatched
// int and Return (foo::*)(ArgTypes...).
foo1.print2b(3); // Error: Can't deduce template parameters, mismatched
// int and Return (foo::*)(ArgTypes...).
foo1.print3(3); // Error: int isn't a pointer-to-member, can't be used with "->*".
And so on...
Of these options, print3() consistently gives the cleanest error messages when misused, making it the best option when everything else is equal. print2b() gives cleaner error messages when called with the wrong number of parameters, but otherwise matches print2a().
Summary:
There are three ways to take a pointer-to-member-function, as described above:
Declare it manually, as described in other answers.
void const foo::print(void const (foo::* f)());
Use templates to specialise it, and take any parameters it might need.
template<typename Return, typename... ArgTypes>
void const foo::print(Return (foo::* f)(ArgTypes...), ArgTypes... args);
Or...
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print(Return (foo::* f)(ArgTypes...), Args... args);
Take the function as a template parameter, and any parameters it may need.
template<typename MemberFunction, typename... Args>
void const foo::print(MemberFunction f, Args... args);
Of these:
The first option gives you the most control over which functions print() is allowed to take, but requires you to explicitly overload it for each type of pointer-to-member-function you want to allow (e.g. void (foo::*)() or int (foo::*)(int, int)); this makes it the least future-proof, because you need to update the function if you add new functions to foo and want it to take them.
The second and third options, conversely, are future-proof, and will take any pointer-to-member-function. However, they don't allow you to restrict what kind of member function you pass, unless you put extra effort into it.
If used incorrectly, the third option will give the cleanest error message, which is useful when troubleshooting. Conversely, the first option will usually emit a conversion error, and the second option will usually emit a "can't deduce template parameters" error. If called with a member function that takes parameters, when not supplied with those parameters, both the third option and the second version of the second option will give the correct error; the third option will emit a cleaner, easier-to-read error, however.
I implemented a C++ equivalent of Python's chain function a while ago thanks to variadic templates. The function is used to iterate successively through many containers. Here is the old working version of the function using a generator named ChainedObject, whatever it is:
template<typename... Iterables>
auto chain(Iterables&&... iters)
-> ChainObject<Iterables...>
{
return /* ... */;
}
And the corresponding main:
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5 };
std::list<int> li = { 6, 7, 8, 9, 10, 11, 12, 13 };
for (auto& i: chain(vec, li))
{
// You can edit a range of iterables
// as if there was only one of them.
i *= 5;
std::cout << i << std::endl;
}
return 0;
}
That main worked fine. We don't care what there is in ChainObject for the problem, so let's see it. I tried to use template templates to ensure that the different collections used had the same value_type and modified the function chain the following way:
template<typename T, template<typename...> class... Iterables>
auto chain(Iterables<T>&&... iters)
-> ChainObject<T, Iterables...>
{
return /* ... */;
}
I thought this would do the trick to ensure the list and vector from my previous main share a same type, but instead, I get the following error from GCC 4.7.1:
In function 'int main()':
error: no matching function for call to 'chain(std::vector&, std::list&)'
note: candidates are:
note: ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]
note: no known conversion for argument 2 from 'std::list<int>' to 'std::list<int>&&'
note: ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]
note: no known conversion for argument 2 from 'std::list<int>' to 'std::list<int>&&'
error: unable to deduce 'auto&' from ''
It seems that the problem comes from argument passing to the function taking rvalue references. However, I really don't understand why my first version worked fine, and note the one using template templates.
Your problem is that the T&& template magic only works for type parameters (it works by deducing T as eg. int& if needed - for lvalue arguments). It can't work for template template arguments, where the actual type is X<T>&& - X must be a class template in this case, not something like "reference-to-class-template". So in the end you have to pass a rvalue-reference, which you cannot implicitly get from a lvalue (variable).
That said, I would suggest you to revert to your earlier code and check that the value_types are the same (or compatible, etc., whatever gets you going) with SFINAE.
Rough code sketch (for strict equality):
template <class ... Ts> struct all_types_equal
{
static const bool value = false;
};
template <class T>
struct all_types_equal<T>
{
static const bool value = true;
};
template <class T, class ... Rest>
struct all_types_equal<T, T, Rest...>
{
static const bool value = all_types_equal<T, Rest...>::value;
};
template<typename... Iterables>
auto chain(Iterables&&... iters)
-> typename std::enable_if<all_types_equal<Iterable::value_type...>::value, ChainObject<Iterables...> >::type
This used to work some weeks ago:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
int main()
{
std::cout << func(10) << std::endl;
return 0;
}
But now g++ -std=c++0x says:
main.cpp: In function ‘constexpr T func(T) [with T = int]’:
main.cpp:29:25: instantiated from here
main.cpp:24:24: error: no matching function for call to ‘tfunc()’
main.cpp:24:24: note: candidate is:
main.cpp:16:14: note: template<class T, T t> T tfunc()
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type]
clang++ -std=c++11 says that template's parameters of tfunc<T, t>() are ignored because invalid.
Is that a bug, or a fix ?
PS:
g++ --version => g++ (GCC) 4.6.2 20120120 (prerelease)
clang++ --version => clang version 3.0 (tags/RELEASE_30/final) (3.0.1)
The parameter t is not a constant expression. Hence the error. It should be also noted that it cannot be a constant expression.
You can pass the constant expression as argument, but inside the function, the object (the parameter) which holds the value, is not a constant expression.
Since t is not a constant expression, it cannot be used as template argument:
return tfunc<T, t>(); //the second argument must be a constant expression
Maybe, you want something like this:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T, T t> //<---- t became template argument!
constexpr T func()
{
return tfunc<T, t>();
}
#define FUNC(a) func<decltype(a),a>()
int main()
{
std::cout << FUNC(10) << std::endl;
}
Now it should work : online demo
I get the feeling that constexpr must also be valid in a 'runtime' context, not just at compile-time. Marking a function as constexpr encourages the compiler to try to evaluate it at compile-time, but the function must still have a valid run-time implementation.
In practice, this means that the compiler doesn't know how to implement this function at runtime:
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
A workaround is to change the constructor such that it takes its t parameter as a normal parameter, not as a template parameter, and mark the constructor as constexpr:
template <typename T>
constexpr T tfunc(T t)
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T>(t);
}
There are three levels of 'constant-expression-ness':
template int parameter, or (non-VLA) array size // Something that must be a constant-expression
constexpr // Something that may be a constant-expression
non-constant-expression
You can't really convert items that are low in that list into something that is high in that list, but obviously the other route it possible.
For example, a call to this function
constexpr int foo(int x) { return x+1; }
isn't necessarily a constant-expression.
// g++-4.6 used in these few lines. ideone doesn't like this code. I don't know why
int array[foo(3)]; // this is OK
int c = getchar();
int array[foo(c)]; // this will not compile (without VLAs)
So the return value from a constexpr function is a constant expression only if all the parameters, and the implementation of the function, can be completed at executed at compile-time.
Recap the question: You have two functions which take a parameter of type T. One takes its parameter as a template parameter, and the other as a 'normal' parameter.
I'm going to call the two functions funcT and funcN instead of tfunc and func.
You wish to be able to call funcT from funcN. Marking the latter as a constexpr doesn't help.
Any function marked as constexpr must be compilable as if the constexpr wasn't there. constexpr functions are a little schizophrenic. They only graduate to full constant-expressions in certain circumstances.
It would not be possible to implement funcN to run at runtime in a simple way, as it would need to be able to work for all possible values of t. This would require the compiler to instantiate many instances of tfunc, one for each value of t. But you can work around this if you're willing to live with a small subset of T. There is a template-recursion limit of 1024 in g++, so you can easily handle 1024 values of T with this code:
#include<iostream>
#include<functional>
#include<array>
using namespace std;
template <typename T, T t>
constexpr T funcT() {
return t + 10;
}
template<typename T, T u>
constexpr T worker (T t) {
return t==0 ? funcT<T,u>() : worker<T, u+1>(t-1);
}
template<>
constexpr int worker<int,1000> (int ) {
return -1;
}
template <typename T>
constexpr T funcN(T t)
{
return t<1000 ? worker<T,0>(t) : -1;
}
int main()
{
std::cout << funcN(10) << std::endl;
array<int, funcN(10)> a; // to verify that funcN(10) returns a constant-expression
return 0;
}
It uses a function worker which will recursively convert the 'normal' parameter t into a template parameter u, which it then uses to instantiate and execute tfunc<T,u>.
The crucial line is return funcT<T,u>() : worker<T, u+1>(t-1);
This has limitations. If you want to use long, or other integral types, you'll have to add another specialization. Obviously, this code only works for t between 0 and 1000 - the exact upper limit is probably compiler-dependent. Another option might be to use a binary search of sorts, with a different worker function for each power of 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
I think this will work around the template-recursion-limit, but it will still require a very large number of instantiations and would make compilation very slow, if it works at all.
Looks like it should give an error - it has no way of knowing that you passed in a constant value as t to func.
More generally, you can't use runtime values as template arguments. Templates are inherently a compile-time construct.