c++: Use template default arugment and check if it is set explicitly - c++

Edit: thanks for the prompt replies. I found my notation about T is confusing.
T is not a template argument but actual type hard coded in the switch clause, according to case.
I have the following template function that takes two template arguments, while the latter is optional:
template <typename F, typename RT = int>
pipe(Input input, F operation)
{
// the Input is a container with its value stored in unknown type T
// and I do the following switch to call different version of
// operation (a template function as well) according to T
switch (input.type())
{
case 0: RT output = (RT) operation<char>(input);break;
case 1: RT output = (RT) operation<int>(input);break;
...
}
return output;
}
What I would like to achieve is to allow determine RT according to the parsed data type T when RT is not explicitly set, i.e.:
when call with pipe<F>(input, operation), the return type would be the same as the data type of input;
when call with pipe<F, RT>(input, operation), the return type would be set to RT regardless what input data type is.
I can achieve this for now by doing overloading, which involves copy paste the nearly the same chunk of code with a little modification
Therefore I am asking if there is a way to avoid this by having a special "dummy" type as the default RT:
template <typename F, typename RT = dummy>
and have some switch in the function pipe like this:
if (RT == dummy)
// use T determined from switch as RT
else
// use the specified RT
Any suggestions?

You should reverse your ordering. If you make the "dummy" template 2nd, to provide it explicitly, you will also have to provide the first type - and then you won't be able to take advantage of template deduction.
Instead, provide two overloads of pipe. One in which RT is explicitly provided:
template <typename RT, typename F>
void pipe(Input input, F operation) {
switch (input.type())
{
case 0: RT output = (RT) operation<char>(input);break;
case 1: RT output = (RT) operation<int>(input);break;
...
}
return output;
}
And one in which it's determined from Input and calls the other one:
template <typename F>
void pipe(Input input, F operation)
{
pipe<typename Input::value_type>(input, operation);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// or whatever metafunction
}
No dummy or need to avoid deduction necessary.

One thing that could actually help you, even if it doesn't answer your question directly is to use the internal typedefs of your container.
All the STL containers have a value_type alias which identify the element which are actually contained within.
Then you can call:
(RT) operation<input::value_type>(input)

Related

How to rewrite template function to allow code reuse

Consider the following template recursion function. Its purpose is to create a vector containing all values in the enum class EnumClassName for which its associated predicate function bool xxx<N>() returns true.
template <EnumClassName N = EnumClassName::LAST_ENUM_VALUE>
std::vector<EnumClassName> xxx_stuff()
{
std::vector<EnumClassName> v = xxx_stuff<EnumClassName(static_cast<int>(N) - 1)>();
if (xxx<N>()) {
v.emplace_back(N);
}
return v;
}
with the recursion base case:
template <> std::vector<EnumClassName> xxx_stuff<EnumClassName::FIRST_ENUM_VALUE>()
{
return {};
}
Now assume there are 10 of these functions where the only thing that differs is the xxx name. I.e. we have the functions alpha_stuff with a corresponding predicate function alpha<N>, beta_stuff with a corresponding predicate function beta<N>, etc etc.
Is there any way to not duplicate the above function 10 times, where the only difference is the replacement of xxx with alpha, beta etc in each duplicate?
I am not able to just loop over the enum values, because the xxx<N> functions in turn call another function yyy<N> which will not accept a runtime-generated template argument <N> (forgive my lingo there, I actually have no idea what I'm talking about or how this works, I just know it gave me compilation errors when I tried it that way).
You cannot pass function template as argument or overloaded function, but you can wrap the call in a type, and then
template <typename EnumClassName,
EnumClassName N = EnumClassName::LAST_ENUM_VALUE,
typename F>
std::vector<EnumClassName> xxx_stuff(F&& f)
{
std::vector<EnumClassName> v =
xxx_stuff<EnumClassName, EnumClassName(static_cast<int>(N) - 1)>(f);
if (f(std::integral_constant<EnumClassName, N>{})) {
v.emplace_back(N);
}
return v;
}
with usage
auto v = xxx_stuff<E>([](auto n) { return xxx<n()>(); });
Demo
Note: That recursion can be avoided using std::integer_sequence.

Specify output_iterator concept as function argument within a concept

I am trying to write some example of a concept that requires implementing a "read" method. This "read" method would take a number of bytes to read and an output iterator to write the data.
So far it looks like this:
template <typename T>
concept DataSourceReader = requires (T reader, std::size_t bytes_to_read) {
{ reader.read(bytes_to_read, std::output_iterator<std::uint8_t>) } -> std::same_as<std::size_t>;
};
However it has multiple issues:
std::output_iterator requires 2 template arguments but I can't figure out what they are
the std::output_iterator argument does not put any constraints (e.g. I can call with any types)
It is also not clear why bytes_to_read need to be in top when { reader.read(5, ...) } works but { reader.read(std::size_t, ...) } does not.
It would seem ok to allow { reader.read(std::same_as<std::size_t>, ...) } since that's how return types can be constrained but it is also wrong.

Make first template argument optional

I have a function that does a base 64 encode using Boost. It takes two template parameters: One for the type of container used for input, and one for the type of container used for output. This allows you to do things like provide binary data using a std::vector but get a std::string back.
Here's the code:
template<typename OutputContainer, typename InputContainer>
OutputContainer Encode(InputContainer const& data)
{
using namespace boost::archive::iterators;
using base64_it = base64_from_binary<transform_width<
typename InputContainer::const_iterator, 6, 8>>;
OutputContainer result(base64_it(data.begin()), base64_it(data.end()));
static std::string const padding[] { "", "==", "="};
auto const& pad = padding[data.size() % 3];
result.insert(result.end(), pad.begin(), pad.end());
return result;
}
Usage example:
std::string data = "Hello World!+";
auto encoded = Encode<std::string>(data);
Live sample here
Note in the example above, I still had to provide the template argument for the output container even though it's the same type as the input container. In these scenarios, I'd like the OutputContainer template parameter to be optional and instead use the type deduced by InputContainer. I am not sure what workarounds or adjustments I can perform to get this kind of interface, but it would be nice to see what SO community can come up with.
Note I am also open to a more iterator-centric approach, but I avoided it due to redundancy/boilerplate (I think it's simpler to pass in containers than iterators). If it ends up looking like the 4-argument version of std::transform() I think I'll be a lot less satisfied with the solution.
Using an overload (not a specialization) for the case where InputContainer and OutputContainer is the same, enable_if to disable the original implementation in this case, it's possible to achieve what you're asking for. A caveat is that it will no longer be possible to explicitly specify both container types if they are the same, unless a third argument is also provided:
template<typename OutputContainer, typename InputContainer, typename = std::enable_if_t<!std::is_same_v<OuptputContainer, InputContainer>>>
OutputContainer Encode(InputContainer const& data)
{
// Your implementation
}
template<typename OutputContainer>
OutputContainer Encode(OutputContainer const& data)
{
return Encode<OutputContainer, OutputContainer, void>(data);
}
Example on Godbolt.

C++ alternative to params object[] in C#

Hello Guys so i want to code something in C++ that i have for C# but as there is no params object in C++ i need some help :P
Ok, so here's what i want to do:
static Int32 Procedure(UInt32 address, params Object[] parameters)
{
Int32 length = parameters.Length;
Int32 index = 0;
UInt32 count = 0;
UInt32 Strings = 0;
UInt32 Single = 0;
UInt32 Array = 0;
while (index < length)
{
if (parameters[index] is Int32)
{
WriteInt32(0x10050000 + (count * 4), (Int32)parameters[index]);
count++;
}
else if(paramaters[index] is String){ }.... // Thats just one thing i wanna use.. i've got more
..........
..........
}
return ReadInt32(0x000000);
}
so i need to figure out what type the parameter is + i wanna use an unknown amount of arguments and i have no idea how i would do this xD
I hope its clear and hopefully someone can Help me :3
Thx, Nico!
You can achieve something similar in C++ with variadic templates. Note that since C++ has no runtime reflection, it's not possible to dynamically get the type of any value: it can only be done at compile-time. Importantly, this also means that you cannot build a parameter list at runtime and pass it to the function without rolling out your own stuff to do it.
It is also arguably much more complicated than a C# equivalent (but then again, if C++ had all the strengths of C# with no weaknesses of itself, nobody would be using C#).
There may be other patterns, but the one I usually use looks like this (example with a print function):
template<typename... T>
void print_all_values(int value, T... values)
{
printf("%i ", value);
print_all_values(values...);
}
template<typename... T>
void print_all_values(double value, T... values)
{
printf("%g ", value);
print_all_values(values...);
}
template<typename... T>
void print_all_values(const char* value, T... values)
{
printf("%s ", value);
print_all_values(values...);
}
template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)
{
printf("(can't print) ");
print_all_values(values...);
}
void print_all_values() {}
print_all_values(4, "hello world", 5.2, nullptr);
// prints: "4 hello world 5.2 (can't print)"
What happens here:
template<typename... T>
void print_all_values
This tells the compiler to create a distinct version of print_all_values for each different parameter type sequences it finds in my program.
void print_all_values(int value, T... values)
void print_all_values(double value, T... values)
void print_all_values(const char* value, T... values)
These differentiate the call per the first parameter. The idea here is that the function will only print its first parameter, then recursively call the template version with the remaining parameters:
{
printf("%s ", value);
print_all_values(values...);
}
At the end of the recursion chain, each parameter has been printed.
For my example print_all_values(4, "hello world", 5.2, nullptr), this is basically what would happen:
print_all_values(4, "hello world", 5.2, nullptr) -> the compiler uses print_all_values(4, ...), at runtime it'll do printf("%i", value), and the call at the end of the function becomes:
print_all_values("hello world", 5.2, nullptr) -> the compiler uses print_all_values("hello world", ...), at runtime it'll do printf("%s", value), and then:
print_all_values(5.2, nullptr) -> the compiler uses print_all_values(5.2, ...), printf("%g", value), then:
print_all_values(5.2, nullptr) -> the compiler can't find a suitable overload, so it falls back to the print_all_values(Unknown&& value, T... values) overload, does "(can't print)", and creates a call to print_all_values(), which does nothing.
The last overload:
template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)
tells the compiler how handle any unknown type (in this case by printing (can't print)). Without this overload, we'd get a compile-time error if we tried to print an unknown type (because it all happens at compile-time, remember).
Did you already try a variadic template declaration like given in the following sample?
template<typename... Args>
static int32_t Procedure(uint32_t address, Args&&... parameters) {
// ...
}
C++ allows you to write functions accepting any number of parameters in the form of variadic template functions:
template<typename... ARGS>
void f( ARGS... args )
{
}
In that example, ARGS and args denote what is known as variadic packs. Neither are a template parameter or an function parameter, are just something that represents a set of template parameters, and a set of function parameters (Respectively).
So that are not parameters, are parameter packs, and then them cannot be manipulated directly. To use the content of a variadic pack, you have to expand the pack with an ellipsis.
Consider the example above: template<typename... ARGS> declares a variadic template with a variadic-pack named ARGS which represents a set of type template parameters.
In the next line, we expand that pack (ARGS...) to use that types as the types of the function argumments. That generates the variadic pack of function argumments args.
To use that argumments inside the function, you should expand args too. Since a pack is just a indetermined set of argumments, you can only use it in contexts where you use the hole set of argumments, in other words, you cannot access directly an specific element of the pack. For example:
template<typename... ARGS>
void f( ARGS... args )
{
f( args... ); //We call f() expanding the args pack of function parameters
//and passing the set of parameters to the function.
}
If you need to traverse the set of parameters in a pack (Which you would do in C# using the subscript operator on the params), you have to use the functional programming way of pattern matching and head-tail recursive list traversing:
template<typename HEAD , typename... TAIL>
void print( const HEAD& head , const TAIL&... tail )
{
std::cout << head << std::endl; //Do something with the head (Which is a
//normal function parameter)
print( tail... ); //Pass the tail to the next call
}
Note that function expects at least one parameter (A variadic template could be empty, but print() has one non-variadic parameter) . You should provide an overload with no parameters to act as base case (The case when there is no more argumments in the argumments list):
void print()
{
//Base case. Does nothing.
}
Now consider the signature of the print() function: Is a function which can take any number of parameters of any combination of types. In contrast to the C# (And Java) approach, storing the parameters in an array of an universal base class, and rely on polymorphism and casting), the C++ approach uses a statically-typed alternative, where the type of each function parameter is well determined at compile time.

transform each element of tuple; get that tuple

I have a tuple in D. I want to apply an element-wise operation on that tuple, and get that transformed tuple for passing into another function that accepts variadic template arguments. The execution path of the transform is defined at compile time, but the actual value is not.
The purpose of this is similar to the template mechanism used in C++'s bind construct, for determining where to use placeholders/passed arguments and where to use stored arguments at compile time.
How do I accomplish this?
this is the first time in D I've ever missed a feature in C++11's template system: the pack/unpack operator - please make me not feel bad :-(
EDIT: Ended up using mixins, because apparently any generic programming solution you want can be solved by using them. May answer with them if no one comes up with anything more elegant than taking D's ridiculously powerful jackhammer-of-a-generic-programming-tool to it.
The element of a tuple can be anything that a template alias parameter can be. However, run-time expressions cannot be alias parameters - they are evaluated at compile time. Thus, it is not possible to transform a tuple using a transformation that runs at compile-time (barring workarounds such as where the transformation defines a #property function that returns the result).
If the expression and transformation can be evaluated at compile-time, see staticMap from std.typetuple.
If I understand the question right, then this is possible but it's a highly experimental (undocumented and not guaranteed to always work) feature:
import std.stdio;
import std.traits;
import std.typetuple;
ReturnType!Call Delay(alias Call, alias arg)() { return Call(arg); }
template Map(alias Call, args...)
{
static if (args.length > 1)
alias Map = TypeTuple!(Delay!(Call, args[0]),Map!(Call, args[1..$]));
else
alias Map = Delay!(Call, args[0]);
}
int square(int arg)
{
return arg * arg;
}
void print(int res1, int res2)
{
writefln("%s %s", res1, res2); // writes '25 100'
}
void test(Args...)(Args args)
{
print(Map!(square, args));
}
void main()
{
int x = 5;
int y = 10;
test(x, y);
}
Originally asked here: Mapping variadic template arguments in D