2

i'm trying to get used to some tmp concepts.

Here is one solution to check if 2 Types are assignable: This is the most important part:

template<typename _Tp, typename _Up>
class __is_assignable_helper: public __sfinae_types {

template<typename _Tp1, typename _Up1>
static decltype(std::declval<_Tp1>() = std::declval<_Up1>(), __one())
__test(int) {}

template<typename, typename>
static __two __test(...) {}

public:
static constexpr bool value = sizeof(__test<_Tp, _Up>(0)) == 1;
};

Now i tried to use some other sfinae tricks but it doesn't work ..

template<typename _Tp, typename _Up, typename = void>
class __is_assignable_helper2
{

public:
static constexpr bool value = false;
};


template<typename _Tp, typename _Up>
class __is_assignable_helper2<_Tp, _Up, 
                                typename std::enable_if<
                                std::is_same<typename
                                decltype(std::declval<_Tp>()=    std::declval<_Up>(), char)
,char >::value
                                                                     , void
                                                        >::type>
{

public:
 static constexpr bool value = true;
};

GCC says: error: wrong number of template arguments (1, should be2) >::value

.. He doesnt accept the decltype as template parameter in is_same.

Could someone explain this error message ? and suggest a solution ?

UPDATE:

OK ! It works ! i wrote char , instead of char{}....

Next Problem:

Is there a more elegant implementation ?

AF_cpp
  • 568
  • 5
  • 15
  • 1
    `std::decltype` should not compile. Did you mean just `decltype`? Also, there's no need for the `typename` keyword here. It's only required if you have a nested name. – dyp Jul 03 '15 at 12:50
  • The going trend these days is to use `void_t`. You can also inherit from `std::integral_constant` or `std::bool_constant` (or I believe Walter Brown inherited from `std::is_same` when implementing this in his CppCon presentation) instead of implementing the boilerplate of the trait. Anyway, you're using [reserved identifiers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). Those names are all the implementers have; don't make it harder for them. – chris Jul 03 '15 at 12:51
  • 1
    The `, char` inside the `decltype` is not an expression. You probably want `, char{}`. – dyp Jul 03 '15 at 12:56
  • Side note: don't prefix your identifiers with `__` or `_` + capital letter. These prefixes are reserved and technically it's undefined behavior. – Anton Savin Jul 03 '15 at 12:57
  • thats it -.- .. thank you and sorry . I really tried my best finding the failure :/ – AF_cpp Jul 03 '15 at 12:58

2 Answers2

2

Here is a possible implementation:

#include<type_traits>
#include<string>

template<typename T, typename U, typename = void>
struct is_assignable: std::false_type {};

template<typename T, typename U>
struct is_assignable<T, U, decltype(std::declval<T>() = std::declval<U>(), void())>: std::true_type {};

int main() {
    static_assert(is_assignable<std::string, const char*>::value, "!");
    static_assert(not is_assignable<const char*, std::string>::value, "!");
    static_assert(is_assignable<int &, int &>::value, "!");
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • @Nik-Lz otherwise `decltype` would give us a type `T`, that isn't `void` and therefore the class template wouldn't result as more specialized. See the third template parameter and it's default value. – skypjack Sep 20 '18 at 17:15
  • I have found a mistake.. `is_assignable::value` and `is_assignable::value` return false (both lvalue and rvalue can be assigned to an lvalue, `std::is_assignable` also agrees with me there). It should return true there. – KeyC0de Sep 20 '18 at 17:34
  • @Nik-Lz it's the comma, did you miss it? – skypjack Sep 20 '18 at 20:04
  • 1
    @Nik-Lz [SO already has all the answers](https://stackoverflow.com/questions/39279074/what-does-the-void-in-decltypevoid-mean-exactly). ;-) – skypjack Sep 20 '18 at 20:08
  • Why do we need `, void()` inside `decltype`? – Ziyuan Aug 24 '22 at 08:59
0

this works for non-fundamental types. I should imagine with a little tweak it can be made to work for int = long conversions etc.

#include <iostream>
#include <utility>
#include <string>

// fallback helper for when the true case won't compile - returns false_type
template<class T, class From>
std::false_type is_assignable_impl(...) { return {}; }

// this overload preferred if decltype(T = From) yields a type   
// returns a true_type
template<class T, class From>
auto
is_assignable_impl(int)
-> decltype(std::declval<T>() = std::declval<From>(), void(), std::true_type())
{ return {}; }

// derived from either false_type or true_type    
template<class T, class From>
struct my_assignable : decltype(is_assignable_impl<T, From>(0)) {};

// a test...
using namespace std;

auto main() -> int
{
    cout << my_assignable<std::string, const char*>::value << endl;
    cout << my_assignable<const char*, std::string>::value << endl;

    return 0;
}

expected output:

1
0
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142