PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label type-inference. Show all posts
Showing posts with label type-inference. Show all posts

Friday, November 4, 2022

[FIXED] How to have template type deduced in std::function arguments with lambda?

 November 04, 2022     c++, c++11, lambda, templates, type-inference     No comments   

Issue

I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

This works well, but I would like the type T to be deduced, so that I can write that:

if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

But the type is not deduced:

type_inference.cpp:19:5: error: no matching function for call to 'if_init'
    if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 
    ^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
    void if_init(Variant& opt_variant, std::function<void(T)> functor){

If I write:

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

it works well.

Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.

I'm using CLang 3.2.

Here is the full test case (the first call compiles not the second):

#include <iostream>
#include <functional>
#include <boost/variant.hpp>

typedef boost::variant<int, double> Test;

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

int main(){
    Test b = 1.44; 

    if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
    if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });      

    return 0;
}

Solution

I recommend you think of std::function<Sig> as a container of any one functor that conforms to Sig as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. std::vector<std::function<Sig>> because such a container can then hold functors of different types.

In your case, because you only care to have just the one functor you really don't need the functionality of std::function<Sig>. As such, I recommend you declare your function template like so:

template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);

If you are worried that this doesn't communicate that Functor must conform to a void(T) signature, please note that std::function<Sig> does not enforce that either: although obviously you will end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.

I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:

// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);

// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);

As to your exact question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.



Answered By - Luc Danton
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Saturday, July 9, 2022

[FIXED] Why is the infer keyword needed in Typescript?

 July 09, 2022     conditional-types, keyword, type-inference, typescript     No comments   

Issue

Why did the Typescript folks create the infer keyword? According to the documents, this is an example of how you would use it:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

I don't understand why this is needed. Why can't it just be:

type ReturnType<T> = T extends (...args: any[]) => R ? R : any;

Why doesn't this work? Why is the infer keyword necessary ?


Solution

With infer, the compiler ensures that you have declared all type variables explicitly:

type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // T1 is { b: string; }

Here we declare a new type variable R in MyType, which gets inferred from T.
(Note, that infer is always used within the extends clause of a conditional type.)

Usage of undeclared type parameters now can result in a compile error:

type MyType2<T> = T extends R2 ? R2 : never; // error, R2 undeclared

Without infer, the compiler wouldn't know, if you wanted to introduce an additional type variable R2 that is to be inferred (see first case), or if R2 is just an accidental typing error/typo. infer exists to remove this ambiguity.

More precisely the compiler checks, if T is assignable to R , when infer is omitted:

type R = { a: number }
type MyType3<T> = T extends R ? R : never; // compare T with type R
type T2 = MyType2<{b: string}> // T2 is never

Note, that infer R shadows type references of an equally-named type declaration R:

type R = { a: number }
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // { b: string; }

Playground



Answered By - ford04
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Sunday, June 26, 2022

[FIXED] How to specify associated type <Item=...> when calling associated function of a trait?

 June 26, 2022     compiler-errors, rust, type-inference     No comments   

Issue

I have this rust code playground:

use itertools::{repeat_n,RepeatN};

pub trait MyIterator: Iterator {
    fn fill1(elem: Self::Item, n1: usize) -> RepeatN<Self::Item>
    where
        Self::Item: Clone,
    {
        repeat_n(elem, n1)
    }
}

My Problem is that I can't call this method because rustc can't infer the type.

// error[E0284]: type annotations needed
// let r: RepeatN<char> = MyIterator::fill1('a', 5);
//                        ^^^^^^^^^^^^^^^^^ cannot infer type
// note: cannot satisfy `<_ as Iterator>::Item == _`
let r: RepeatN<char> = MyIterator::fill1('a', 5);

I tried this but it doesn't compile:

// error[E0229]: associated type bindings are not allowed here
let r: RepeatN<char> = MyIterator::<Item=char>::fill1('a', 5);

How can I specify the type of Item in this call? Or is a function outside of the trait (like itertools::repeat_n) the best way here?


Solution

Well, you haven't implemented the trait for any types, so no fill1 function actually exists.

If you implement MyIterator for some type that implements Iterator<Item = char>, for example std::iter::Empty<char>, then you'll be able to call fill1 through that type.

use std::iter::Empty;
impl MyIterator for Empty<char> {}

fn main() {
    let r: RepeatN<char> = Empty::fill1('a', 5);
}

This is, however, pointless. You will note that Empty plays no role in the actual function definition - it could have been any iterator. Furthermore there is no sensible generalization of this behavior to other Self types. This is why itertools::repeat_n is not a member of the Itertools trait: it is nonsense as a trait function because it is not a generalization of behavior shared by multiple iterator types.

In Rust, unlike some other languages, not everything has to be a member of a class. If you merely want to put fill1 and related things in a common namespace, simply use a module, which is the most basic unit of code organization.

mod my_iterator {
    use itertools::{repeat_n, RepeatN};

    fn fill1<T>(elem: T, n1: usize) -> RepeatN<T>
    where
        T: Clone,
    {
        repeat_n(elem, n1)
    }
}


Answered By - trent
Answer Checked By - Clifford M. (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing