SFINEA and implicit type conversion

Hi,

lately I started to dig deeper into templates and SFINEA.
In my project I was able to use SFINEA to do basically what I want.
But there is one exception.

I want to enable a function only if operator<<(ostream, Type) is available. I want it for exactly that type, not for any implicit conversion.

Below you find some sample C++ (17) code, that works. But in my project
I do not want it to work. Operator<< is not available for foo.

Do you have any ideads?

Regards,
mathes

[SOLVED]
See first post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <ostream>
#include <type_traits>
#include <utility>


class foo final
{
  public:
    operator int() const
    {   
        return 42; 
    }   
};

template <typename T, typename = std::void_t<>>
struct detector : std::false_type
{
};

template <typename T>
struct detector<T, std::void_t<
    std::enable_if_t
    <   
        std::is_same_v
        <   
            std::ostream,
            std::remove_reference_t
            <   
                decltype(operator<<(std::declval<std::ostream>(), std::declval<T>())) // changed, T was foo before. Thanks Peter87
            >   
        >   
    >>> : std::true_type
{
};

template <typename T>
auto print(T&& val) -> std::enable_if_t<detector<T>::value>
{
    std::cout << val << std::endl;
}

int main()
{
    foo x;
    print(x);
}

Last edited on
Instead of std::declval<foo>() I guess you meant to write std::declval<T>().

To disable implicit conversions you could use a class that can be implicit convertible to T.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template<typename T>
struct abc // I have no idea what to call this sort of thing.
{
    operator T() const;
};

template <typename T>
struct detector<T, std::void_t<
    std::enable_if_t
    <   
        std::is_same_v
        <   
            std::ostream,
            std::remove_reference_t
            <   
                decltype(operator<<(std::declval<std::ostream>(), std::declval<abc<T>>()))
            >   
        >   
    >>> : std::true_type
{
};


I think this should work because the compiler won't do more than one implicit conversion. Forcing an implicit conversion to T would hence disable implicit conversions from T.
Last edited on
Hi Peter,

you are absolutely right, it should be declval<T> instead of declval<foo>. I will change the code above.

As I see your solution I understand it, but I was not able to come up with it.

Thank you very much!

Regards,
Mathes
Last edited on
Topic archived. No new replies allowed.